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

📄 ftp.cpp

📁 一个用QT开发的FTP客户端
💻 CPP
📖 第 1 页 / 共 5 页
字号:
  kDebug(7102) << "Ftp::stat : cleaned path='" << path << "'";  // We can't stat root, but we know it's a dir.  if( path.isEmpty() || path == "/" )  {    UDSEntry entry;    //entry.insert( KIO::UDSEntry::UDS_NAME, UDSField( QString() ) );    entry.insert( KIO::UDSEntry::UDS_NAME, QString::fromLatin1( "." ) );    entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );    entry.insert( KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH );    entry.insert( KIO::UDSEntry::UDS_USER, QString::fromLatin1( "root" ) );    entry.insert( KIO::UDSEntry::UDS_GROUP, QString::fromLatin1( "root" ) );    // no size    statEntry( entry );    finished();    return;  }  KUrl tempurl( url );  tempurl.setPath( path ); // take the clean one  QString listarg; // = tempurl.directory(KUrl::ObeyTrailingSlash);  QString parentDir;  QString filename = tempurl.fileName();  Q_ASSERT(!filename.isEmpty());  QString search = filename;  // Try cwd into it, if it works it's a dir (and then we'll list the parent directory to get more info)  // if it doesn't work, it's a file (and then we'll use dir filename)  bool isDir = ftpFolder(path, false);  // if we're only interested in "file or directory", we should stop here  QString sDetails = metaData("details");  int details = sDetails.isEmpty() ? 2 : sDetails.toInt();  kDebug(7102) << "Ftp::stat details=" << details;  if ( details == 0 )  {     if ( !isDir && !ftpSize( path, 'I' ) ) // ok, not a dir -> is it a file ?     {  // no -> it doesn't exist at all        ftpStatAnswerNotFound( path, filename );        return;     }     ftpShortStatAnswer( filename, isDir ); // successfully found a dir or a file -> done     return;  }  if (!isDir)  {    // It is a file or it doesn't exist, try going to parent directory    parentDir = tempurl.directory(KUrl::AppendTrailingSlash);    // With files we can do "LIST <filename>" to avoid listing the whole dir    listarg = filename;  }  else  {    // --- New implementation:    // Don't list the parent dir. Too slow, might not show it, etc.    // Just return that it's a dir.    UDSEntry entry;    entry.insert( KIO::UDSEntry::UDS_NAME, filename );    entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR );    entry.insert( KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH );    // No clue about size, ownership, group, etc.    statEntry(entry);    finished();    return;    // --- Old implementation:#if 0    // It's a dir, remember that    // Reason: it could be a symlink to a dir, in which case ftpReadDir    // in the parent dir will have no idea about that. But we know better.    isDir = true;    // If the dir starts with '.', we'll need '-a' to see it in the listing.    if ( search[0] == '.' )       listarg = "-a";    parentDir = "..";#endif  }  // Now cwd the parent dir, to prepare for listing  if( !ftpFolder(parentDir, true) )    return;  if( !ftpOpenCommand( "list", listarg, 'I', ERR_DOES_NOT_EXIST ) )  {    kError(7102) << "COULD NOT LIST";    return;  }  kDebug(7102) << "Starting of list was ok";  Q_ASSERT( !search.isEmpty() && search != "/" );  bool bFound = false;  KUrl      linkURL;  FtpEntry  ftpEnt;  while( ftpReadDir(ftpEnt) )  {    // We look for search or filename, since some servers (e.g. ftp.tuwien.ac.at)    // return only the filename when doing "dir /full/path/to/file"    if ( !bFound )    {        if ( ( search == ftpEnt.name || filename == ftpEnt.name ) ) {            if ( !filename.isEmpty() ) {              bFound = true;              UDSEntry entry;              ftpCreateUDSEntry( filename, ftpEnt, entry, isDir );              statEntry( entry );            }        }#if 0 // goes with the "old implementation" above        else if ( isDir && ( ftpEnt.name == listarg || ftpEnt.name+'/' == listarg ) ) {            // Damn, the dir we're trying to list is in fact a symlink            // Follow it and try again            if ( ftpEnt.link.isEmpty() )                kWarning(7102) << "Got " << listarg << " as answer, but empty link!";            else            {                linkURL = url;                kDebug(7102) << "ftpEnt.link=" << ftpEnt.link;                if ( ftpEnt.link[0] == '/' )                    linkURL.setPath( ftpEnt.link ); // Absolute link                else                {                    // Relative link (stat will take care of cleaning ../.. etc.)                    linkURL.setPath( listarg ); // this is what we were listing (the link)                    linkURL.setPath( linkURL.directory() ); // go up one dir                    linkURL.addPath( ftpEnt.link ); // replace link by its destination                    kDebug(7102) << "linkURL now " << linkURL.prettyUrl();                }                // Re-add the filename we're looking for                linkURL.addPath( filename );            }            bFound = true;        }#endif    }    // kDebug(7102) << ftpEnt.name;  }  ftpCloseCommand();        // closes the data connection only  if ( !bFound )  {    ftpStatAnswerNotFound( path, filename );    return;  }  if ( !linkURL.isEmpty() )  {      if ( linkURL == url || linkURL == tempurl )      {          error( ERR_CYCLIC_LINK, linkURL.prettyUrl() );          return;      }      stat( linkURL );      return;  }  kDebug(7102) << "stat : finished successfully";  finished();}void Ftp::listDir( const KUrl &url ){  kDebug(7102) << "Ftp::listDir " << url.prettyUrl();  if( !ftpOpenConnection(loginImplicit) )        return;  // No path specified ?  QString path = url.path();  if ( path.isEmpty() )  {    KUrl realURL;    realURL.setProtocol( "ftps" );    if ( m_user != FTP_LOGIN )      realURL.setUser( m_user );    // We set the password, so that we don't ask for it if it was given    if ( m_pass != FTP_PASSWD )      realURL.setPass( m_pass );    realURL.setHost( m_host );    if ( m_port > 0 && m_port != DEFAULT_FTP_PORT )        realURL.setPort( m_port );    if ( m_initialPath.isEmpty() )        m_initialPath = "/";    realURL.setPath( m_initialPath );    kDebug(7102) << "REDIRECTION to " << realURL.prettyUrl();    redirection( realURL );    finished();    return;  }  kDebug(7102) << "hunting for path '" << path << "'";  if (!ftpOpenDir( path ) )  {    if ( ftpSize( path, 'I' ) ) // is it a file ?    {      error( ERR_IS_FILE, path );      return;    }    // not sure which to emit    //error( ERR_DOES_NOT_EXIST, path );    error( ERR_CANNOT_ENTER_DIRECTORY, path );    return;  }  UDSEntry entry;  FtpEntry  ftpEnt;  while( ftpReadDir(ftpEnt) )  {    //kDebug(7102) << ftpEnt.name;    //Q_ASSERT( !ftpEnt.name.isEmpty() );    if ( !ftpEnt.name.isEmpty() )    {      //if ( S_ISDIR( (mode_t)ftpEnt.type ) )      //   kDebug(7102) << "is a dir";      //if ( !ftpEnt.link.isEmpty() )      //   kDebug(7102) << "is a link to " << ftpEnt.link;      entry.clear();      ftpCreateUDSEntry( ftpEnt.name, ftpEnt, entry, false );      listEntry( entry, false );    }  }  listEntry( entry, true ); // ready  ftpCloseCommand();        // closes the data connection only  finished();}void Ftp::slave_status(){  kDebug(7102) << "Got slave_status host = " << (!m_host.toAscii().isEmpty() ? m_host.toAscii() : "[None]") << " [" << (m_bLoggedOn ? "Connected" : "Not connected") << "]";  slaveStatus( m_host, m_bLoggedOn );}bool Ftp::ftpOpenDir( const QString & path ){  //QString path( _url.path(KUrl::RemoveTrailingSlash) );  // We try to change to this directory first to see whether it really is a directory.  // (And also to follow symlinks)  QString tmp = path.isEmpty() ? QString("/") : path;  // We get '550', whether it's a file or doesn't exist...  if( !ftpFolder(tmp, false) )      return false;  // Don't use the path in the list command:  // We changed into this directory anyway - so it's enough just to send "list".  // We use '-a' because the application MAY be interested in dot files.  // The only way to really know would be to have a metadata flag for this...  // Since some windows ftp server seems not to support the -a argument, we use a fallback here.  // In fact we have to use -la otherwise -a removes the default -l (e.g. ftp.trolltech.com)  if( !ftpOpenCommand( "list -la", QString(), 'I', ERR_CANNOT_ENTER_DIRECTORY ) )  {    if ( !ftpOpenCommand( "list", QString(), 'I', ERR_CANNOT_ENTER_DIRECTORY ) )    {      kWarning(7102) << "Can't open for listing";      return false;    }  }  kDebug(7102) << "Starting of list was ok";  return true;}bool Ftp::ftpReadDir(FtpEntry& de){  assert(m_data != NULL);  // get a line from the data connecetion ...  while( true )  {    while (!m_data->canReadLine() && m_data->waitForReadyRead()) {}    QByteArray data = m_data->readLine();    if (data.size() == 0)      break;    const char* buffer = data.data();    kDebug(7102) << "dir > " << buffer;    //Normally the listing looks like    // -rw-r--r--   1 dfaure   dfaure        102 Nov  9 12:30 log    // but on Netware servers like ftp://ci-1.ci.pwr.wroc.pl/ it looks like (#76442)    // d [RWCEAFMS] Admin                     512 Oct 13  2004 PSI    // we should always get the following 5 fields ...    const char *p_access, *p_junk, *p_owner, *p_group, *p_size;    if( (p_access = strtok((char*)buffer," ")) == 0) continue;    if( (p_junk  = strtok(NULL," ")) == 0) continue;    if( (p_owner = strtok(NULL," ")) == 0) continue;    if( (p_group = strtok(NULL," ")) == 0) continue;    if( (p_size  = strtok(NULL," ")) == 0) continue;    //kDebug(7102) << "p_access=" << p_access << " p_junk=" << p_junk << " p_owner=" << p_owner << " p_group=" << p_group << " p_size=" << p_size;    de.access = 0;    if ( strlen( p_access ) == 1 && p_junk[0] == '[' ) { // Netware      de.access = S_IRWXU | S_IRWXG | S_IRWXO; // unknown -> give all permissions    }    const char *p_date_1, *p_date_2, *p_date_3, *p_name;    // A special hack for "/dev". A listing may look like this:    // crw-rw-rw-   1 root     root       1,   5 Jun 29  1997 zero    // So we just ignore the number in front of the ",". Ok, its a hack :-)    if ( strchr( p_size, ',' ) != 0L )    {      //kDebug(7102) << "Size contains a ',' -> reading size again (/dev hack)";      if ((p_size = strtok(NULL," ")) == 0)        continue;    }    // Check whether the size we just read was really the size    // or a month (this happens when the server lists no group)    // Used to be the case on sunsite.uio.no, but not anymore    // This is needed for the Netware case, too.    if ( !isdigit( *p_size ) )    {      p_date_1 = p_size;      p_size = p_group;      p_group = 0;      //kDebug(7102) << "Size didn't have a digit -> size=" << p_size << " date_1=" << p_date_1;    }    else    {      p_date_1 = strtok(NULL," ");      //kDebug(7102) << "Size has a digit -> ok. p_date_1=" << p_date_1;    }    if ( p_date_1 != 0 &&         (p_date_2 = strtok(NULL," ")) != 0 &&         (p_date_3 = strtok(NULL," ")) != 0 &&         (p_name = strtok(NULL,"\r\n")) != 0 )    {      {        QByteArray tmp( p_name );        if ( p_access[0] == 'l' )        {          int i = tmp.lastIndexOf( " -> " );          if ( i != -1 ) {            de.link = remoteEncoding()->decode(p_name + i + 4);            tmp.truncate( i );          }          else            de.link.clear();        }        else          de.link.clear();        if ( tmp[0] == '/' ) // listing on ftp://ftp.gnupg.org/ starts with '/'          tmp.remove( 0, 1 );        if (tmp.indexOf('/') != -1)          continue; // Don't trick us!        // Some sites put more than one space between the date and the name        // e.g. ftp://ftp.uni-marburg.de/mirror/        de.name     = remoteEncoding()->decode(tmp.trimmed());      }      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' || p_access[3] == 's' )        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' || p_access[6] == 's' )        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' || p_access[9] == 't' )        de.access |= S_IXOTH;      if ( p_access[3] == 's' || p_access[3] == 'S' )        de.access |= S_ISUID;      if ( p_access[6] == 's' || p_access[6] == 'S' )        de.access |= S_ISGID;      if ( p_access[9] == 't' || p_access[9] == 'T' )        de.access |= S_ISVTX;      de.owner    = remoteEncoding()->decode(p_owner);      de.group    = remoteEncoding()->decode(p_group);      de.size     = charToLongLong(p_size);      // 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( &currentTime );      int currentMonth = tmptr->tm_mon;      //kDebug(7102) << "Current time :" << asctime( tmptr );      // 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      //kDebug(7102) << "Looking for month " << p_date_1;      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]) )        {          //kDebug(7102) << "Found month " << c << " for " << p_date_1;          tmptr->tm_mon = c;          break;        }

⌨️ 快捷键说明

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