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

📄 ftpsite.cpp

📁 很好用的ftp源码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/*****************************************************************************\
 *    ftpsite.cpp - Internal object that manages a single FTP site
\*****************************************************************************/

#include "priv.h"
#include "ftpsite.h"
#include "ftpinet.h"
#include "ftpurl.h"
#include "statusbr.h"
#include "offline.h"
#include <ratings.h>
#include <wininet.h>
#include <dbgmem.h>

#ifdef DEBUG
DWORD g_dwOpenConnections = 0;      // Ref Counting Open Connections
#endif // DEBUG

/*****************************************************************************\
 *    CFtpSite
 *
 *    EEK!  RFC 1738 is really scary.  FTP sites don't necessarily
 *    start you at the root, and RFC1738 says that ftp://foo/bar asks
 *    for the file bar in the DEFAULT directory, not the root!
\*****************************************************************************/
CFtpList * g_FtpSiteCache = NULL;                /* The list of all open FTP sites */


void CFtpSite::FlushHint(void)
{
    HINTERNET hint = m_hint;

    m_hint = NULL;
    if (hint)
    {
        // Our caller needs to be holding the critical section
        // while we modify m_hint
        ASSERTCRITICAL;

        InternetCloseHandle(hint);
//        DEBUG_CODE(g_dwOpenConnections--;);
    }
}


void CFtpSite::FlushHintCritial(void)
{
    ASSERTNONCRITICAL;

    ENTERCRITICAL;
    FlushHint();
    LEAVECRITICAL;
}


void CFtpSite::FlushHintCB(LPVOID pvFtpSite)
{
    CFtpSite * pfs = (CFtpSite *) pvFtpSite;

    if (pfs)
    {
        pfs->FlushHint();
        pfs->Release();
    }
}


/*****************************************************************************\
 *    An InternetConnect has just completed.  Get the motd and cache it.
 *
 *    hint - the connected handle, possibly 0 if error
\*****************************************************************************/
void CFtpSite::CollectMotd(HINTERNET hint)
{
    CFtpGlob * pfg = GetFtpResponse(&m_cwe);
    remove_from_memlist(pfg);   // We will probably free this on a separate thread.

    ENTERCRITICAL;
    m_fMotd = m_pfgMotd ? TRUE : FALSE;            // We have a motd

    IUnknown_Set(&m_pfgMotd, NULL);
    m_pfgMotd = pfg;

    LEAVECRITICAL;
}


/*****************************************************************************\
    FUNCTION: ReleaseHint

    DESCRIPTION:
        An FtpDir client is finished with a handle to the FTP site.
    Put it into the cache, and throw away what used to be there.

    We always keep the most recent handle, because that reduces the
    likelihood that the server will close the connection due to extended
    inactivity.

    The critical section around this entire procedure is important,
    else we open up all sorts of really ugly race conditions.  E.g.,
    the timeout might trigger before we're finished initializing it.
    Or somebody might ask for the handle before we're ready.
\*****************************************************************************/
void CFtpSite::ReleaseHint(LPCITEMIDLIST pidlFtpPath, HINTERNET hint)
{
    ENTERCRITICAL;

    TriggerDelayedAction(&m_hgti);    // Kick out the old one

    _SetPidl(pidlFtpPath);
    m_hint = hint;

    if (EVAL(SUCCEEDED(SetDelayedAction(FlushHintCB, (LPVOID) this, &m_hgti))))
        AddRef();   // We just gave away a ref.
    else
        FlushHint();    // Oh well, can't cache it

    LEAVECRITICAL;
}


// NT #362108: We need to set the redirect password for the CFtpSite that
// contains the server, the user name, but a blank password to be redirected
// to the CFtpSite that does have the correct password.  This way, if a user
// logs in and doesn't save the password in the URL or the secure cache, we
// then put it in the in memory password cache so it stays valid for that
// "browser" session (defined by process lifetime).  We then need to redirect
// future navigations that go to that 
HRESULT CFtpSite::_SetRedirPassword(LPCTSTR pszServer, INTERNET_PORT ipPortNum, LPCTSTR pszUser, LPCTSTR pszPassword, LPCITEMIDLIST pidlFtpPath, LPCTSTR pszFragment)
{
    TCHAR szUrl[MAX_URL_STRING];
    HRESULT hr;

    hr = UrlCreate(pszServer, pszUser, TEXT(""), TEXT(""), pszFragment, ipPortNum, NULL, szUrl, ARRAYSIZE(szUrl));
    if (EVAL(SUCCEEDED(hr)))
    {
        LPITEMIDLIST pidlServer;

        hr = CreateFtpPidlFromUrl(szUrl, GetCWireEncoding(), NULL, &pidlServer, m_pm, TRUE);
        if (EVAL(SUCCEEDED(hr)))
        {
            LPITEMIDLIST pidl = ILCombine(pidlServer, pidlFtpPath);

            if (pidl)
            {
                CFtpSite * pfsDest = NULL;

                // The user name has changed so we need to update the
                // CFtpSite with the new user name also.
                hr = SiteCache_PidlLookup(pidl, FALSE, m_pm, &pfsDest);
                if (EVAL(SUCCEEDED(hr)))
                {
                    pfsDest->SetRedirPassword(pszPassword);
                    pfsDest->Release();
                }

                ILFree(pidl);
            }

            ILFree(pidlServer);
        }
    }

    return hr;
}

HRESULT CFtpSite::_RedirectAndUpdate(LPCTSTR pszServer, INTERNET_PORT ipPortNum, LPCTSTR pszUser, LPCTSTR pszPassword, LPCITEMIDLIST pidlFtpPath, LPCTSTR pszFragment, IUnknown * punkSite, CFtpFolder * pff)
{
    TCHAR szUrl[MAX_URL_STRING];
    TCHAR szUser[INTERNET_MAX_USER_NAME_LENGTH];
    HRESULT hr;

    StrCpyN(szUser, pszUser, ARRAYSIZE(szUser));    // Copy because of possible reentrancy
    EscapeString(NULL, szUser, ARRAYSIZE(szUser));
    hr = UrlCreate(pszServer, szUser, pszPassword, TEXT(""), pszFragment, ipPortNum, NULL, szUrl, ARRAYSIZE(szUrl));
    if (EVAL(SUCCEEDED(hr) && pff))
    {
        LPITEMIDLIST pidlServer;

        hr = CreateFtpPidlFromUrl(szUrl, GetCWireEncoding(), NULL, &pidlServer, m_pm, TRUE);
        if (EVAL(SUCCEEDED(hr)))
        {
            LPITEMIDLIST pidl = ILCombine(pidlServer, pidlFtpPath);

            if (pidl)
            {
                // If the user changed the password, we need to setup a redirect so
                // they can return later. (NT #362108)
                if (m_pszUser && !StrCmp(m_pszUser, szUser) && StrCmp(m_pszPassword, pszPassword))
                {
                    _SetRedirPassword(pszServer, ipPortNum, szUser, pszPassword, pidlFtpPath, pszFragment);
                }

                // If the user name changed, set a redirect.
                if (!m_pszUser || StrCmp(m_pszUser, szUser))
                {
                    CFtpSite * pfsDest = NULL;

                    // The user name has changed so we need to update the
                    // CFtpSite with the new user name also.
                    hr = SiteCache_PidlLookup(pidl, FALSE, m_pm, &pfsDest);
                    if (EVAL(SUCCEEDED(hr)))
                    {
                        pfsDest->SetRedirPassword(pszPassword);
                        pfsDest->Release();
                    }
                }

                hr = _Redirect(pidl, punkSite, pff);
                ILFree(pidl);
            }

            ILFree(pidlServer);
        }
    }

    return hr;
}


HRESULT CFtpSite::_Redirect(LPITEMIDLIST pidl, IUnknown * punkSite, CFtpFolder * pff)
{
    LPITEMIDLIST pidlFull = pff->CreateFullPublicPidl(pidl);
    HRESULT hr = E_INVALIDARG;

    if (EVAL(pidlFull))
    {
        hr = IUnknown_PidlNavigate(punkSite, pidlFull, FALSE);

        ASSERT(SUCCEEDED(hr));
        ILFree(pidlFull);
    }

    return hr;
}


/*****************************************************************************\
    FUNCTION: _SetDirectory

    DESCRIPTION:
        When the caller wants a handle to the server, they often want a different
    directory than what's in the cache.  This function needs to change into
    the new directory.
\*****************************************************************************/
HRESULT CFtpSite::_SetDirectory(HINTERNET hint, HWND hwnd, LPCITEMIDLIST pidlNewDir, CStatusBar * psb, int * pnTriesLeft)
{
    HRESULT hr = S_OK;

    if (pidlNewDir && FtpID_IsServerItemID(pidlNewDir))
        pidlNewDir = _ILNext(pidlNewDir);   // Skip the server.

    ASSERT(m_pidl);
    // NT #300889: I would like to cache the dir but sometimes it gets
    //             out of wack and m_pidl doesn't match the HINTERNET's
    //             cwd.  PERF: This could be fixed in the future but
    //             this perf tweak isn't work the work now (small gain).
//  if (m_pidl && !FtpPidl_IsPathEqual(_ILNext(m_pidl), pidlNewDir))
    {
        LPITEMIDLIST pidlWithVirtualRoot;

        if (psb)
        {
            WCHAR wzDisplayPath[MAX_PATH];  // For Statusbar.
            
            if (pidlNewDir && SUCCEEDED(GetDisplayPathFromPidl(pidlNewDir, wzDisplayPath, ARRAYSIZE(wzDisplayPath), TRUE)))
                psb->SetStatusMessage(IDS_CHDIR, wzDisplayPath);
            else
                psb->SetStatusMessage(IDS_CHDIR, L"\\");
        }

        hr = PidlInsertVirtualRoot(pidlNewDir, &pidlWithVirtualRoot);
        if (EVAL(SUCCEEDED(hr)))
        {
            hr = FtpSetCurrentDirectoryPidlWrap(hint, TRUE, pidlWithVirtualRoot, TRUE, TRUE);
            if (SUCCEEDED(hr))  // Ok if failed. (No Access?)
            {
                hr = _SetPidl(pidlNewDir);
            }
            else
            {

                ReleaseHint(NULL, hint); // Nowhere
                if (hr == HRESULT_FROM_WIN32(ERROR_FTP_DROPPED))
                    FlushHintCritial(); // Don't cache dead hint
                else
                {
                    DisplayWininetError(hwnd, TRUE, HRESULT_CODE(hr), IDS_FTPERR_TITLE_ERROR, IDS_FTPERR_CHANGEDIR, IDS_FTPERR_WININET, MB_OK, NULL);
                    *pnTriesLeft = 0;   // Make sure we don't keep display UI.
                    hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
                }

                hint = 0;
            }

            ILFree(pidlWithVirtualRoot);
        }

        if (psb)
            psb->SetStatusMessage(IDS_EMPTY, 0);
    }

    return hr;
}


/*****************************************************************************\
    FUNCTION: _LoginToTheServer

    DESCRIPTION:
        We want an HINTERNET to do some FTP operation but we don't have one
    cached.  So, login to create it.

    WARNING: This function will be called in a critical section and needs to 
             return in one.  However, it may leave the critical section for a
             while.
\*****************************************************************************/
HRESULT CFtpSite::_LoginToTheServer(HWND hwnd, HINTERNET hintDll, HINTERNET * phint, LPCITEMIDLIST pidlFtpPath, CStatusBar * psb, IUnknown * punkSite, CFtpFolder * pff)
{
    HRESULT hr = S_OK;

    ASSERTCRITICAL;
    BOOL fKeepTryingToLogin = FALSE;
    BOOL fTryOldPassword = TRUE;

    LEAVECRITICALNOASSERT;
    TCHAR szUser[INTERNET_MAX_USER_NAME_LENGTH];
    TCHAR szPassword[INTERNET_MAX_PASSWORD_LENGTH];

    StrCpyN(szUser, m_pszUser, ARRAYSIZE(szUser));
    StrCpyN(szPassword, m_pszPassword, ARRAYSIZE(szPassword));

    ASSERT(m_pszServer);
    if (psb)
        psb->SetStatusMessage(IDS_CONNECTING, m_pszServer);

    do
    {
        hr = InternetConnectWrap(hintDll, TRUE, HANDLE_NULLSTR(m_pszServer), m_ipPortNum, NULL_FOR_EMPTYSTR(szUser), NULL_FOR_EMPTYSTR(szPassword), INTERNET_SERVICE_FTP, 0, 0, phint);
        if (*phint)
            fKeepTryingToLogin = FALSE; // Move up.
        else
        {
            BOOL fSkipLoginDialog = FALSE;

            // Display Login dialog to get new user name/password to try again or cancel login.
            // fKeepTryingToLogin = TRUE if Dialog said [LOGIN].
            if (((ERROR_INTERNET_LOGIN_FAILURE == HRESULT_CODE(hr)) ||
                (ERROR_INTERNET_INCORRECT_USER_NAME == HRESULT_CODE(hr)) ||
                (ERROR_INTERNET_INCORRECT_PASSWORD == HRESULT_CODE(hr))) && hwnd)
            {
                BOOL fIsAnonymous = (!szUser[0] || !StrCmpI(szUser, TEXT("anonymous")) ? TRUE : FALSE);
                DWORD dwLoginFlags = (fIsAnonymous ? LOGINFLAGS_ANON_LOGINJUSTFAILED : LOGINFLAGS_USER_LOGINJUSTFAILED);

                if (fTryOldPassword)
                {

⌨️ 快捷键说明

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