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

📄 ftp.cpp

📁 A*算法 A*算法 A*算法 A*算法A*算法A*算法
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/////////////////////////////////////////////////////////////////////////////
// Name:        common/ftp.cpp
// Purpose:     FTP protocol
// Author:      Guilhem Lavaux
// Modified by: Mark Johnson, wxWindows@mj10777.de
//              20000917 : RmDir, GetLastResult, GetList
//              Vadim Zeitlin (numerous fixes and rewrites to all part of the
//              code, support ASCII/Binary modes, better error reporting, more
//              robust Abort(), support for arbitrary FTP commands, ...)
//              Randall Fox (support for active mode)
// Created:     07/07/1997
// RCS-ID:      $Id: ftp.cpp,v 1.61 2005/05/31 09:19:50 JS Exp $
// Copyright:   (c) 1997, 1998 Guilhem Lavaux
//              (c) 1998-2004 wxWidgets team
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// ============================================================================
// declarations
// ============================================================================

#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
  #pragma implementation "ftp.h"
#endif

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
  #pragma hdrstop
#endif

#if wxUSE_PROTOCOL_FTP

#ifndef WX_PRECOMP
    #include <stdlib.h>
    #include "wx/string.h"
    #include "wx/utils.h"
    #include "wx/log.h"
    #include "wx/intl.h"
#endif // WX_PRECOMP

#include "wx/sckaddr.h"
#include "wx/socket.h"
#include "wx/url.h"
#include "wx/sckstrm.h"
#include "wx/protocol/protocol.h"
#include "wx/protocol/ftp.h"

#if defined(__WXMAC__)
    #include "wx/mac/macsock.h"
#endif

#ifndef __MWERKS__
    #include <memory.h>
#endif

// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------

// the length of FTP status code (3 digits)
static const size_t LEN_CODE = 3;

// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------

IMPLEMENT_DYNAMIC_CLASS(wxFTP, wxProtocol)
IMPLEMENT_PROTOCOL(wxFTP, wxT("ftp"), wxT("ftp"), true)

// ============================================================================
// implementation
// ============================================================================

// ----------------------------------------------------------------------------
// wxFTP constructor and destructor
// ----------------------------------------------------------------------------

wxFTP::wxFTP()
{
    m_lastError = wxPROTO_NOERR;
    m_streaming = false;
    m_currentTransfermode = NONE;

    m_user = wxT("anonymous");
    m_passwd << wxGetUserId() << wxT('@') << wxGetFullHostName();

    SetNotify(0);
    SetFlags(wxSOCKET_NONE);
    m_bPassive = true;
    SetDefaultTimeout(60); // Default is Sixty Seconds
    m_bEncounteredError = false;
}

wxFTP::~wxFTP()
{
    if ( m_streaming )
    {
        // if we are streaming, this will issue
        // an FTP ABORT command, to tell the server we are aborting
        (void)Abort();
    }

    // now this issues a "QUIT" command to tell the server we are
    Close();
}

// ----------------------------------------------------------------------------
// wxFTP connect and login methods
// ----------------------------------------------------------------------------

bool wxFTP::Connect(wxSockAddress& addr, bool WXUNUSED(wait))
{
    if ( !wxProtocol::Connect(addr) )
    {
        m_lastError = wxPROTO_NETERR;
        return false;
    }

    if ( !m_user )
    {
        m_lastError = wxPROTO_CONNERR;
        return false;
    }

    // we should have 220 welcome message
    if ( !CheckResult('2') )
    {
        Close();
        return false;
    }

    wxString command;
    command.Printf(wxT("USER %s"), m_user.c_str());
    char rc = SendCommand(command);
    if ( rc == '2' )
    {
        // 230 return: user accepted without password
        return true;
    }

    if ( rc != '3' )
    {
        Close();
        return false;
    }

    command.Printf(wxT("PASS %s"), m_passwd.c_str());
    if ( !CheckCommand(command, '2') )
    {
        Close();
        return false;
    }

    return true;
}

bool wxFTP::Connect(const wxString& host)
{
    wxIPV4address addr;
    addr.Hostname(host);
    addr.Service(wxT("ftp"));

    return Connect(addr);
}

bool wxFTP::Close()
{
    if ( m_streaming )
    {
        m_lastError = wxPROTO_STREAMING;
        return false;
    }

    if ( IsConnected() )
    {
        if ( !CheckCommand(wxT("QUIT"), '2') )
        {
            wxLogDebug(_T("Failed to close connection gracefully."));
        }
    }

    return wxSocketClient::Close();
}

// ============================================================================
// low level methods
// ============================================================================

// ----------------------------------------------------------------------------
// Send command to FTP server
// ----------------------------------------------------------------------------

char wxFTP::SendCommand(const wxString& command)
{
    if ( m_streaming )
    {
        m_lastError = wxPROTO_STREAMING;
        return 0;
    }

    wxString tmp_str = command + wxT("\r\n");
    const wxWX2MBbuf tmp_buf = tmp_str.mb_str();
    if ( Write(wxMBSTRINGCAST tmp_buf, strlen(tmp_buf)).Error())
    {
        m_lastError = wxPROTO_NETERR;
        return 0;
    }

#ifdef __WXDEBUG__
    // don't show the passwords in the logs (even in debug ones)
    wxString cmd, password;
    if ( command.Upper().StartsWith(_T("PASS "), &password) )
    {
        cmd << _T("PASS ") << wxString(_T('*'), password.length());
    }
    else
    {
        cmd = command;
    }

    wxLogTrace(FTP_TRACE_MASK, _T("==> %s"), cmd.c_str());
#endif // __WXDEBUG__

    return GetResult();
}

// ----------------------------------------------------------------------------
// Recieve servers reply
// ----------------------------------------------------------------------------

char wxFTP::GetResult()
{
    // if we've already had a read or write timeout error, the connection is
    // probably toast, so don't bother, it just wastes the users time
    if ( m_bEncounteredError )
        return 0;

    wxString code;

    // m_lastResult will contain the entire server response, possibly on
    // multiple lines
    m_lastResult.clear();

    // we handle multiline replies here according to RFC 959: it says that a
    // reply may either be on 1 line of the form "xyz ..." or on several lines
    // in whuch case it looks like
    //      xyz-...
    //      ...
    //      xyz ...
    // and the intermeidate lines may start with xyz or not
    bool badReply = false;
    bool firstLine = true;
    bool endOfReply = false;
    while ( !endOfReply && !badReply )
    {
        wxString line;
        m_lastError = ReadLine(this,line);
        if ( m_lastError )
        {
            m_bEncounteredError = true;
            return 0;
        }

        if ( !m_lastResult.empty() )
        {
            // separate from last line
            m_lastResult += _T('\n');
        }

        m_lastResult += line;

        // unless this is an intermediate line of a multiline reply, it must
        // contain the code in the beginning and '-' or ' ' following it
        if ( line.Len() < LEN_CODE + 1 )
        {
            if ( firstLine )
            {
                badReply = true;
            }
            else
            {
                wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"),
                           code.c_str(), line.c_str());
            }
        }
        else // line has at least 4 chars
        {
            // this is the char which tells us what we're dealing with
            wxChar chMarker = line.GetChar(LEN_CODE);

            if ( firstLine )
            {
                code = wxString(line, LEN_CODE);
                wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"),
                           code.c_str(), line.c_str() + LEN_CODE + 1);

                switch ( chMarker )
                {
                    case _T(' '):
                        endOfReply = true;
                        break;

                    case _T('-'):
                        firstLine = false;
                        break;

                    default:
                        // unexpected
                        badReply = true;
                }
            }
            else // subsequent line of multiline reply
            {
                if ( wxStrncmp(line, code, LEN_CODE) == 0 )
                {
                    if ( chMarker == _T(' ') )
                    {
                        endOfReply = true;
                    }

                    wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"),
                               code.c_str(), line.c_str() + LEN_CODE + 1);
                }
                else
                {
                    // just part of reply
                    wxLogTrace(FTP_TRACE_MASK, _T("<== %s %s"),
                               code.c_str(), line.c_str());
                }
            }
        }
    }

    if ( badReply )
    {
        wxLogDebug(_T("Broken FTP server: '%s' is not a valid reply."),
                   m_lastResult.c_str());

        m_lastError = wxPROTO_PROTERR;

        return 0;
    }

    // if we got here we must have a non empty code string
    return (char)code[0u];
}

// ----------------------------------------------------------------------------
// wxFTP simple commands
// ----------------------------------------------------------------------------

bool wxFTP::SetTransferMode(TransferMode transferMode)
{
    if ( transferMode == m_currentTransfermode )
    {
        // nothing to do
        return true;
    }

    wxString mode;
    switch ( transferMode )
    {
        default:
            wxFAIL_MSG(_T("unknown FTP transfer mode"));
            // fall through

        case BINARY:
            mode = _T('I');
            break;

        case ASCII:
            mode = _T('A');
            break;
    }

    if ( !DoSimpleCommand(_T("TYPE"), mode) )
    {
        wxLogError(_("Failed to set FTP transfer mode to %s."), (const wxChar*)
                   (transferMode == ASCII ? _("ASCII") : _("binary")));

        return false;
    }

    // If we get here the operation has been successfully completed
    // Set the status-member
    m_currentTransfermode = transferMode;

    return true;
}

bool wxFTP::DoSimpleCommand(const wxChar *command, const wxString& arg)
{
    wxString fullcmd = command;
    if ( !arg.empty() )
    {
        fullcmd << _T(' ') << arg;
    }

    if ( !CheckCommand(fullcmd, '2') )
    {
        wxLogDebug(_T("FTP command '%s' failed."), fullcmd.c_str());

        return false;
    }

    return true;
}

bool wxFTP::ChDir(const wxString& dir)
{
    // some servers might not understand ".." if they use different directory
    // tree conventions, but they always understand CDUP - should we use it if
    // dir == ".."? OTOH, do such servers (still) exist?

    return DoSimpleCommand(_T("CWD"), dir);
}

bool wxFTP::MkDir(const wxString& dir)
{
    return DoSimpleCommand(_T("MKD"), dir);
}

bool wxFTP::RmDir(const wxString& dir)
{
    return DoSimpleCommand(_T("RMD"), dir);
}

wxString wxFTP::Pwd()
{
    wxString path;

    if ( CheckCommand(wxT("PWD"), '2') )
    {
        // the result is at least that long if CheckCommand() succeeded
        const wxChar *p = m_lastResult.c_str() + LEN_CODE + 1;
        if ( *p != _T('"') )
        {
            wxLogDebug(_T("Missing starting quote in reply for PWD: %s"), p);
        }
        else
        {
            for ( p++; *p; p++ )
            {
                if ( *p == _T('"') )
                {
                    // check if the quote is doubled
                    p++;
                    if ( !*p || *p != _T('"') )
                    {
                        // no, this is the end
                        break;
                    }
                    //else: yes, it is: this is an embedded quote in the
                    //      filename, treat as normal char
                }

                path += *p;
            }

            if ( !*p )
            {
                wxLogDebug(_T("Missing ending quote in reply for PWD: %s"),
                           m_lastResult.c_str() + LEN_CODE + 1);
            }
        }
    }
    else
    {
        wxLogDebug(_T("FTP PWD command failed."));
    }

    return path;
}

bool wxFTP::Rename(const wxString& src, const wxString& dst)
{
    wxString str;

    str = wxT("RNFR ") + src;
    if ( !CheckCommand(str, '3') )
        return false;

    str = wxT("RNTO ") + dst;

    return CheckCommand(str, '2');
}

bool wxFTP::RmFile(const wxString& path)
{
    wxString str;
    str = wxT("DELE ") + path;

    return CheckCommand(str, '2');
}

// ----------------------------------------------------------------------------
// wxFTP download and upload
// ----------------------------------------------------------------------------

class wxInputFTPStream : public wxSocketInputStream
{

⌨️ 快捷键说明

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