ftp.cc
来自「konqueror3 embedded版本, KDE环境下的当家浏览器的嵌入式版」· CC 代码 · 共 2,199 行 · 第 1/5 页
CC
2,199 行
if(loginMode == loginImplicit && m_bLoggedOn) { assert(m_control != NULL); // must have control connection socket return true; } kdDebug(7102) << "ftpOpenConnection " << m_host << ":" << m_port << " " << m_user << " [password hidden]" << endl; infoMessage( i18n("Opening connection to host %1").arg(m_host) ); if ( m_host.isEmpty() ) { error( ERR_UNKNOWN_HOST, QString::null ); return false; } assert( !m_bLoggedOn ); m_initialPath = QString::null; m_currentPath = QString::null; QString host = m_bUseProxy ? m_proxyURL.host() : m_host; unsigned short int port = m_bUseProxy ? m_proxyURL.port() : m_port; if (!ftpOpenControlConnection(host, port) ) return false; // error emitted by ftpOpenControlConnection infoMessage( i18n("Connected to host %1").arg(m_host) ); if(loginMode != loginDefered) { m_bLoggedOn = ftpLogin(); if( !m_bLoggedOn ) return false; // error emitted by ftpLogin } m_bTextMode = config()->readBoolEntry("textmode", false); connected(); return true;}/** * Called by @ref openConnection. It opens the control connection to the ftp server. * * @return true on success. */bool Ftp::ftpOpenControlConnection( const QString &host, unsigned short int port ){ if ( port == 0 ) { struct servent *pse; if ( ( pse = getservbyname( "ftp", "tcp" ) ) == NULL ) port = 21; else port = ntohs(pse->s_port); } // implicitly close, then try to open a new connection ... closeConnection(); int iErrorCode = ERR_OUT_OF_MEMORY; QString sErrorMsg; m_control = new FtpSocket("CNTL"); if(m_control != NULL) { // now connect to the server and read the login message ... m_control->setAddress(host, port); iErrorCode = m_control->connectSocket(connectTimeout(), true); sErrorMsg = host; // on connect success try to read the server message... if(iErrorCode == 0) { const char* psz = ftpResponse(-1); if(m_iRespType != 2) { // login not successful, do we have an message text? if(psz[0]) sErrorMsg = i18n("%1.\n\nReason: %2").arg(host).arg(psz); iErrorCode = ERR_COULD_NOT_CONNECT; } } } // 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()->readBoolEntry("EnableAutoLogin") ) { 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 ); info.url.setPort( m_port ); info.url.setUser( user ); QCString 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; kdDebug(7102) << "Prompting user for login info..." << endl; // 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" ).arg(user).arg(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>").arg( m_host ); info.keepPassword = true; // Prompt the user for persistence as well. info.readOnly = (!m_user.isEmpty() && m_user != FTP_LOGIN); bool disablePassDlg = config()->readBoolEntry( "DisablePassDlg", false ); if ( disablePassDlg || !openPassDlg( info, errorMsg ) ) { error( ERR_USER_CANCELED, m_host ); return false; } else { user = info.username; pass = info.password; } } tempbuf = "user "; tempbuf += user.latin1(); if ( m_bUseProxy ) { tempbuf += '@'; tempbuf += m_host.latin1(); if ( m_port > 0 && m_port != DEFAULT_FTP_PORT ) { tempbuf += ':'; tempbuf += QString::number(m_port).latin1(); } } kdDebug(7102) << "Sending Login name: " << tempbuf << endl; 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 ) { kdDebug(7102) << "Login failed: " << ftpResponse(0) << endl; ++failedAuth; continue; // Well we failed, prompt the user please!! } if( needPass ) { tempbuf = "pass "; tempbuf += pass.latin1(); kdDebug(7102) << "Sending Login password: " << "[protected]" << endl; 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 ); kdDebug(7102) << "Login OK" << endl; 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 S鴊aard) 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 kdWarning(7102) << "syst failed" << endl; if ( config()->readBoolEntry ("EnableAutoLoginMacro") ) ftpAutoLoginMacro (); // Get the current working directory kdDebug(7102) << "Searching for pwd" << endl; if( !ftpSendCmd("pwd") || (m_iRespType != 2) ) { kdDebug(7102) << "Couldn't issue pwd command" << endl; error( ERR_COULD_NOT_LOGIN, i18n("Could not login to %1.").arg(m_host) ); // or anything better ? return false; } QString sTmp = remoteEncoding()->decode( ftpResponse(3) ); int iBeg = sTmp.find('"'); int iEnd = sTmp.findRev('"'); if(iBeg > 0 && iBeg < iEnd) { m_initialPath = sTmp.mid(iBeg+1, iEnd-iBeg-1); if(m_initialPath[0] != '/') m_initialPath.prepend('/'); kdDebug(7102) << "Initial path set to: " << m_initialPath << endl; m_currentPath = m_initialPath; } return true;}void Ftp::ftpAutoLoginMacro (){ QString macro = metaData( "autoLoginMacro" ); if ( macro.isEmpty() ) return; QStringList list = QStringList::split('\n', macro); for(QStringList::Iterator it = list.begin() ; it != list.end() ; ++it ) { if ( (*it).startsWith("init") ) { list = QStringList::split( '\\', macro); 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).stripWhiteSpace(), 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 QCString& cmd, int maxretries ){ assert(m_control != NULL); // must have control connection socket if ( cmd.find( '\r' ) != -1 || cmd.find( '\n' ) != -1) { kdWarning(7102) << "Invalid command received (contains CR or LF):" << cmd.data() << endl; error( ERR_UNSUPPORTED_ACTION, m_host ); return false; } // Don't print out the password... bool isPassCmd = (cmd.left(4).lower() == "pass"); if ( !isPassCmd ) kdDebug(7102) << "send> " << cmd.data() << endl; else kdDebug(7102) << "send> pass [protected]" << endl; // Send the message... QCString buf = cmd; buf += "\r\n"; // Yes, must use CR/LF - see http://cr.yp.to/ftp/request.html int num = m_control->write(buf.data(), buf.length()); // 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; m_control->textClear(); } // 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 { kdDebug(7102) << "Was not able to communicate with " << m_host << endl << "Attempting to re-establish connection." << endl; closeConnection(); // Close the old connection... openConnection(); // Attempt to re-establish a new connection... if (!m_bLoggedOn) { if (m_control != NULL) // if openConnection succeeded ... { kdDebug(7102) << "Login failure, aborting" << endl; error (ERR_COULD_NOT_LOGIN, m_host); closeConnection (); } return false; } kdDebug(7102) << "Logged back in, re-issuing command" << endl; // 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 1 if successful, 0 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 const KSocketAddress *sa = m_control->peerAddress(); if (sa != NULL && sa->family() != PF_INET) 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) ) { kdDebug(7102) << "PASV attempt failed" << endl; // unknown command? if( m_iRespType == 5 ) { kdDebug(7102) << "disabling use of PASV" << endl; 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]; char *start = strchr(ftpResponse(3), '('); if ( !start ) start = strchr(ftpResponse(3), '='); if ( !start ||
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?