📄 ftp.cc
字号:
#include "ftp.h"#include <errno.h>#include <assert.h>#include <kio_interface.h>#include <iostream.h>#define FTP_LOGIN "anonymous"#define FTP_PASSWD "kfm-user@kde.org"const char* strnextchr( const char * p , char c );bool open_PassDlg( const char *_head, string& _user, string& _pass );Ftp::Ftp(){ dirfile = 0L; sControl = sData = sDatal = 0; ftplib_debug = 9; m_error = 0; m_errorText = ""; m_bLoggedOn = false; m_bPersistent = false;}Ftp::~Ftp(){ ftpDisconnect();}/* * read a line of text * * return -1 on error or bytecount */int Ftp::readline(char *buf,int max,netbuf *ctl){ int x,retval = 0; char *end; int eof = 0; if ( max == 0 ) return 0; do { if (ctl->cavail > 0) { x = (max >= ctl->cavail) ? ctl->cavail : max-1; end = (char*)memccpy(buf,ctl->cget,'\n',x); if (end != NULL) x = end - buf; retval += x; buf += x; *buf = '\0'; max -= x; ctl->cget += x; ctl->cavail -= x; if (end != NULL) break; } if (max == 1) { *buf = '\0'; break; } if (ctl->cput == ctl->cget) { ctl->cput = ctl->cget = ctl->buf; ctl->cavail = 0; ctl->cleft = FTP_BUFSIZ; } if (eof) { if (retval == 0) retval = -1; break; } if ((x = ::read(ctl->handle,ctl->cput,ctl->cleft)) == -1) { perror("read"); retval = -1; break; } if (x == 0) eof = 1; ctl->cleft -= x; ctl->cavail += x; ctl->cput += x; } while (1); return retval;}/* * read a response from the server * * return 0 if first char doesn't match * return 1 if first char matches */bool Ftp::readresp(char c){ char match[5]; if ( readline( rspbuf, 256, nControl ) == -1 ) { if ( ftplib_debug > 1) fprintf( stderr,"Could not read\n" ); m_error = ERR_COULD_NOT_READ; m_errorText = ""; return false; } if ( ftplib_debug > 1) fprintf(stderr,"resp> %s",rspbuf); if ( rspbuf[3] == '-' ) { strncpy( match, rspbuf, 3 ); match[3] = ' '; match[4] = '\0'; do { if ( readline( rspbuf, 256, nControl ) == -1 ) { m_error = ERR_COULD_NOT_READ; m_errorText = ""; return false; } if ( ftplib_debug > 1) fprintf(stderr,"%s",rspbuf); } while ( strncmp( rspbuf, match, 4 ) ); } if ( rspbuf[0] == c ) return true; return false;}/* * disconnect from remote */void Ftp::ftpDisconnect(){ if ( m_bPersistent ) return; if ( m_bLoggedOn ) { if( sControl != 0 ) { ftpSendCmd( "quit", '2' ); free( nControl ); ::close( sControl ); sControl = 0; } } m_bLoggedOn = false;}bool Ftp::ftpConnect( K2URL& _url ){ string dummy; return ftpConnect( _url.host(), _url.port(), _url.user(), _url.pass(), dummy );} /** * login on remote host */bool Ftp::ftpConnect( const char *_host, int _port, const char *_user, const char *_pass, string& _path ){ m_bPersistent = false; // ProtocolManager::self()->isPersistent(); if ( m_bLoggedOn ) if ( m_bPersistent ) { // this should check whether there is still opened data connection. // is it enough ? Should we check also the control connection ? if ( ftpOpenDataConnection() ) return true; } else assert( !m_bLoggedOn ); _path = ""; if ( !ftpConnect2( _host ) ) { if ( !m_error ) { m_error = ERR_COULD_NOT_CONNECT; m_errorText = _host; } return false; } string user; string passwd; if( _user && strlen( _user ) > 0 ) { user = _user; if ( _pass && strlen( _pass ) > 0 ) passwd = _pass; else passwd = ""; } else { user = FTP_LOGIN; passwd = FTP_PASSWD; } if ( ftplib_debug > 2 ) fprintf( stderr, "Connected ....\n" ); string redirect = ""; m_bLoggedOn = ftpLogin( user.c_str(), passwd.c_str(), &redirect ); if ( !m_bLoggedOn ) { if ( ftplib_debug > 2 ) fprintf( stderr, "Could not login\n" ); m_error = ERR_COULD_NOT_LOGIN; m_errorText = _host; return false; } // We could login and got a redirect ? if ( !redirect.empty() ) { if ( redirect[ redirect.size() - 1 ] != '/' ) redirect += "/"; _path = redirect; if ( ftplib_debug > 2 ) fprintf( stderr, "REDIRECTION '%s'\n",redirect.c_str()); } m_bLoggedOn = true; return true;}/* * ftpOpen - connect to remote server * * return 1 if connected, 0 if not */bool Ftp::ftpConnect2( const char *host, int _port ){ struct sockaddr_in sin; struct hostent *phe; struct servent *pse; int on = 1; m_host = ""; memset( &sin, 0, sizeof( sin ) ); sin.sin_family = AF_INET; if ( _port == -1 && ( pse = getservbyname( "ftp", "tcp" ) ) == NULL ) _port = 21; else if ( _port == -1 ) sin.sin_port = pse->s_port; if ( ( phe = gethostbyname( host ) ) == NULL ) { m_error = ERR_UNKNOWN_HOST; m_errorText = host; return false; } memcpy((char *)&sin.sin_addr, phe->h_addr, phe->h_length); sControl = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); if ( sControl == 0 ) { m_error = ERR_COULD_NOT_CREATE_SOCKET; m_errorText = host; } if ( setsockopt( sControl, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on) ) == -1 ) { ::close( sControl ); m_error = ERR_COULD_NOT_CREATE_SOCKET; m_errorText = host; } if ( ::connect(sControl, (struct sockaddr *)&sin, sizeof(sin)) == -1) { ::close( sControl ); m_error = ERR_COULD_NOT_CONNECT; m_errorText = host; return false; } nControl = (netbuf*)calloc(1,sizeof(netbuf)); if (nControl == NULL) { ::close( sControl ); m_error = ERR_OUT_OF_MEMORY; m_errorText = ""; return false; } nControl->handle = sControl; if ( readresp( '2' ) == 0 ) { ::close( sControl ); free( nControl ); return false; } m_host = host; return true;}/* * ftpLogin - log in to remote server * * return 1 if logged in, 0 otherwise */bool Ftp::ftpLogin( const char *_user, const char *_pass, string *_redirect ){ assert( !m_bLoggedOn ); string user = _user; string pass = _pass; if ( !user.empty() ) { string tempbuf = "user "; tempbuf += user; rspbuf[0] = '\0'; if ( !ftpSendCmd( tempbuf.c_str(), '3' ) ) { if ( ftplib_debug > 2 ) fprintf( stderr, "1> %s\n", rspbuf ); if ( rspbuf[0] == '2' ) return true; /* no password required */ return false; } if ( pass.empty() ) { string tmp; tmp = user; tmp += "@"; tmp += m_host; if ( !open_PassDlg( tmp.c_str(), user, pass ) ) return false; } cerr << "New pass is '" << pass << "'" << endl; tempbuf = "pass "; tempbuf += pass; if ( !ftpSendCmd( tempbuf.c_str(), '2' ) ) { cerr << "Wrong password" << endl; return false; } } cerr << "Login ok" << endl; // Not interested in the current working directory ? => return with success if ( _redirect == 0L ) return true; cerr << "Searching for pwd" << endl; // Get the current working directory string tempbuf = "pwd"; if ( !ftpSendCmd( tempbuf.c_str(), '2' ) ) return false; if ( ftplib_debug > 2 ) fprintf( stderr, "2> %s\n", rspbuf ); char *p = rspbuf; while ( isdigit( *p ) ) p++; while ( *p == ' ' || *p == '\t' ) p++; if ( *p != '"' ) return true; char *p2 = strchr( p + 1, '"' ); if ( p2 == 0L ) return true; *p2 = 0; *_redirect = p + 1; return true;}/* * ftpSendCmd - send a command and wait for expected response * * return 1 if proper response received, 0 otherwise */bool Ftp::ftpSendCmd( const char *cmd, char expresp ){ assert( sControl > 0 ); string buf = cmd; buf += "\r\n"; if ( ftplib_debug > 2 ) fprintf( stderr, "%s\n", cmd ); if ( ::write( sControl, buf.c_str(), buf.size() ) <= 0 ) { m_error = ERR_COULD_NOT_WRITE; m_errorText = ""; return false; } return readresp( expresp );}/* * ftpOpenDataConnection - set up date connection * * return 1 if successful, 0 otherwise */bool Ftp::ftpOpenDataConnection(){ assert( m_bLoggedOn ); union { struct sockaddr sa; struct sockaddr_in in; } sin; struct linger lng = { 0, 0 }; ksize_t l; char buf[64]; int on = 1; l = sizeof(sin); if ( getsockname( sControl, &sin.sa, &l ) < 0 ) return false; sDatal = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); if ( sDatal == 0 ) { m_error = ERR_COULD_NOT_CREATE_SOCKET; m_errorText = ""; return false; } if ( setsockopt( sDatal, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on) ) == -1 ) { ::close( sDatal ); m_error = ERR_COULD_NOT_CREATE_SOCKET; m_errorText = ""; return false; } if ( setsockopt( sDatal, SOL_SOCKET, SO_LINGER, (char*)&lng, sizeof(lng) ) == -1 ) { ::close( sDatal ); m_error = ERR_COULD_NOT_CREATE_SOCKET; m_errorText = ""; return false; } sin.in.sin_port = 0; if ( bind( sDatal, &sin.sa, sizeof(sin) ) == -1 ) { ::close( sDatal ); sDatal = 0; m_error = ERR_COULD_NOT_BIND; m_errorText = m_host; return false; } if ( listen( sDatal, 1 ) < 0 ) { m_error = ERR_COULD_NOT_LISTEN; m_errorText = m_host; ::close( sDatal ); sDatal = 0; return 0; } if ( getsockname( sDatal, &sin.sa, &l ) < 0 ) return false; sprintf(buf,"port %d,%d,%d,%d,%d,%d", (unsigned char)sin.sa.sa_data[2],(unsigned char)sin.sa.sa_data[3], (unsigned char)sin.sa.sa_data[4],(unsigned char)sin.sa.sa_data[5], (unsigned char)sin.sa.sa_data[0],(unsigned char)sin.sa.sa_data[1]); return ftpSendCmd( buf, '2' );}/* * accept_connect - wait for incoming connection * * return -2 on error or timeout * otherwise returns socket descriptor */int Ftp::ftpAcceptConnect(void){ struct sockaddr addr; int sData; ksize_t l; fd_set mask; FD_ZERO(&mask); FD_SET(sDatal,&mask); if (select( sDatal + 1, &mask, NULL, NULL, 0L) == 0) { ::close( sDatal ); return -2; } l = sizeof(addr); if ( ( sData = accept( sDatal, &addr, &l ) ) > 0 ) return sData; ::close( sDatal ); return -2;}bool Ftp::ftpPort(){ string buf = "type A"; if ( !ftpSendCmd( buf.c_str(), '2' ) ) { m_error = ERR_COULD_NOT_CONNECT; m_errorText = ""; return false; } if ( !ftpOpenDataConnection() ) { m_error = ERR_COULD_NOT_CONNECT; m_errorText = ""; return false; } return true;}bool Ftp::ftpOpenCommand( const char *_command, const char *_path, char _mode, unsigned long _offset ){ string buf; buf = "type "; char buf2[2] = {0,0}; buf2[0] = _mode; buf += buf2; if ( !ftpSendCmd( buf.c_str(), '2' ) ) { m_error = ERR_COULD_NOT_CONNECT; m_errorText = ""; return false; } if ( !ftpOpenDataConnection() ) { m_error = ERR_COULD_NOT_CONNECT; m_errorText = ""; return false; } string tmp; // Special hack for the list command. We try to change to this // directory first to see whether it really is a directory. if ( strcmp( _command, "list" ) == 0 ) { assert( _path != 0L ); tmp = "cwd "; tmp += _path; if ( !ftpSendCmd( tmp.c_str(), '2' ) ) { if ( !m_error && rspbuf[0] == '5' ) { m_error = ERR_IS_FILE; m_errorText = _path; } else if ( !m_error ) { m_error = ERR_DOES_NOT_EXIST; m_errorText = _path; } return false; } } else if ( _offset > 0 ) { // send rest command if offset > 0, this applies to retr and stor commands char buf[100]; sprintf(buf, "rest %ld", _offset); if ( !ftpSendCmd( buf, '3' ) ) { if ( ! m_error )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -