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

📄 ftpdir.cpp

📁 很好用的ftp源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************\
    FILE: ftpdir.cpp

    DESCRIPTION:
        Internal object that manages a single FTP directory

    The idea is that each FtpSite maintains a linked list of the
    FtpDir's that it owns.  Gets and Releases are done through the
    FtpSite.  Each FtpDir retains a non-refcounted pointer back
    to the FtpSite that owns it.

    The reason this is necessary is that there might be multiple
    IShellFolder's all looking at the same physical directory.  Since
    enumerations are expensive, we cache the enumeration information
    here, so that each IShellFolder client can use the information.

    This also lets us hold the motd, so that multiple clients can
    query for the motd without constantly pinging the site.
\*****************************************************************************/


#include "priv.h"
#include "ftpdir.h"
#include "ftpsite.h"
#include "ftppidl.h"
#include "ftpurl.h"
#include "ftppidl.h"
#include "statusbr.h"


/*****************************************************************************\
    FUNCTION: GetDisplayPath

    DESCRIPTION:
\*****************************************************************************/
HRESULT CFtpDir::GetDisplayPath(LPWSTR pwzDisplayPath, DWORD cchSize)
{
    return GetDisplayPathFromPidl(m_pidlFtpDir, pwzDisplayPath, cchSize, FALSE);
}


/*****************************************************************************\
    FUNCTION: CollectMotd

    DESCRIPTION:
        An InternetConnect has just completed.  Get the motd and cache it.

    hint - the connected handle, possibly 0 if error
\*****************************************************************************/
void CFtpDir::CollectMotd(HINTERNET hint)
{
    CFtpGlob * pfg = GetFtpResponse(GetFtpSite()->GetCWireEncoding());

    if (m_pfgMotd)
        m_pfgMotd->Release();

    m_pfgMotd = pfg;  // m_pfgMotd will take pfg's ref.
}


/*****************************************************************************\
    FUNCTION: CollectMotd

    DESCRIPTION:
        Shove a value into the cached list.
\*****************************************************************************/
void CFtpDir::SetCache(CFtpPidlList * pflHfpl)
{
    IUnknown_Set(&m_pflHfpl, pflHfpl);

    // If we are flushing the cache, then flush the Ratings info also.
    // This way the user can reenter the parent password if wanted.
    if (!pflHfpl && m_pfs)
        m_pfs->FlushRatingsInfo();
}


/*****************************************************************************\
    FUNCTION: CollectMotd

    DESCRIPTION:
        Get the value out of the cache.
\*****************************************************************************/
CFtpPidlList * CFtpDir::GetHfpl(void)
{
    CFtpPidlList * pfl;
    
    pfl = m_pflHfpl;
    if (pfl)
        pfl->AddRef();

    return pfl;
}


/*****************************************************************************\
    FUNCTION: CollectMotd

    DESCRIPTION:
        Get the FTP site associated with a directory.
    This doesn't AddRef the return value.
\*****************************************************************************/
CFtpSite * CFtpDir::GetFtpSite(void)
{
    return m_pfs;
}


CFtpDir * CFtpDir::GetSubFtpDir(CFtpFolder * pff, LPCITEMIDLIST pidl, BOOL fPublic)
{
    CFtpDir * pfd = NULL;

    if (EVAL(pidl))
    {
        LPITEMIDLIST pidlChild = GetSubPidl(pff, pidl, fPublic);
        
        if (EVAL(pidlChild))
        {
            m_pfs->GetFtpDir(pidlChild, &pfd);
            ILFree(pidlChild);
        }
    }

    return pfd;
}


LPITEMIDLIST CFtpDir::GetSubPidl(CFtpFolder * pff, LPCITEMIDLIST pidlRelative, BOOL fPublic)
{
    LPITEMIDLIST pidlRoot = ((fPublic && pff) ? pff->GetPublicPidlRootIDClone() : NULL);
    LPITEMIDLIST pidlPublic = ILCombine(pidlRoot, m_pidl);
    LPITEMIDLIST pidlFull = NULL;

    if (pidlPublic)
    {
        pidlFull = ILCombine(pidlPublic, pidlRelative);
        ILFree(pidlPublic);
    }

    ILFree(pidlRoot);
    return pidlFull;
}


HRESULT CFtpDir::AddItem(LPCITEMIDLIST pidl)
{
    if (!m_pflHfpl)
        return S_OK;

#ifdef DEBUG
#if 0
    WCHAR wzDisplayPath[MAX_PATH];

    EVAL(SUCCEEDED(GetDisplayPathFromPidl(m_pidlFtpDir, wzDisplayPath, ARRAYSIZE(wzDisplayPath), FALSE)));

    TraceMsg(TF_ALWAYS, "CFtpDir::AddItem() Dir=\"%ls\", Item=\"%ls\".", wzDisplayPath, FtpPidl_GetFileDisplayName(pidl));
#endif // 0
#endif // DEBUG

    return m_pflHfpl->InsertSorted(pidl);
}


/*****************************************************************************\
    FUNCTION: CollectMotd

    DESCRIPTION:
        Get a HINTERNET for this directory.
\*****************************************************************************/
HRESULT CFtpDir::GetHint(HWND hwnd, CStatusBar * psb, HINTERNET * phint, IUnknown * punkSite, CFtpFolder * pff)
{
    HRESULT hr = m_pfs->GetHint(hwnd, m_pidlFtpDir, psb, phint, punkSite, pff);

    return hr;
}


/*****************************************************************************\
    FUNCTION: CollectMotd

    DESCRIPTION:
        Give a HINTERNET back to the FtpSite.
\*****************************************************************************/
void CFtpDir::ReleaseHint(HINTERNET hint)
{
    ASSERT(!hint || m_pfs); // If we have a hint to release, we need to call ::ReleaseHint()
    if (m_pfs)
        m_pfs->ReleaseHint(m_pidlFtpDir, hint);
}


/*****************************************************************************\
    FUNCTION: CollectMotd

    DESCRIPTION:
        Perform an operation with a temporary internet handle which is
    already connected to the site and resides in the correct directory.
\*****************************************************************************/
STDMETHODIMP CFtpDir::WithHint(CStatusBar * psb, HWND hwnd, HINTPROC hp, LPCVOID pv, IUnknown * punkSite, CFtpFolder * pff)
{
    HRESULT hr = E_FAIL;

    // Did the user turn off FTP Folders?
    // If so, don't connect.  This will fix NT #406423 where the user turned
    // of FTP Folders because they have a firewall (CISCO filtering Router)
    // that will kill packets in such a way the caller (WinSock/Wininet) needs
    // to wait for a timeout.  During this timeout, the browser will hang causing
    // the user to think it crashed.
    if (!SHRegGetBoolUSValue(SZ_REGKEY_FTPFOLDER, SZ_REGKEY_USE_OLD_UI, FALSE, FALSE))
    {
        HINTERNET hint;
        HINTPROCINFO hpi;

        ASSERTNONCRITICAL;        // Cannot do psb (CStatusBar *) with the crst
        ASSERT(m_pfs);
        hpi.pfd = this;
        hpi.hwnd = hwnd;
        hpi.psb = psb;

        hr = GetHint(hwnd, psb, &hint, punkSite, pff);
        if (SUCCEEDED(hr)) // Ok if fails
        {
            BOOL fReleaseHint = TRUE;

            if (hp)
                hr = hp(hint, &hpi, (LPVOID)pv, &fReleaseHint);

            if (fReleaseHint)
                ReleaseHint(hint);
        }
    }

    return hr;
}


/*****************************************************************************\
    FUNCTION: _SetNameOfCB

    DESCRIPTION:
        If we were able to rename the file, return the output pidl.
    Also tell anybody who cares that this LPITEMIDLIST needs to be refreshed.

    The "A" emphasizes that the filename is received in ANSI.

    _UNDOCUMENTED_: The documentation on SetNameOf's treatment of
    the source pidl is random.  It seems to suggest that the source
    pidl is ILFree'd by SetNameOf, but it isn't.
\*****************************************************************************/
HRESULT CFtpDir::_SetNameOfCB(HINTERNET hint, HINTPROCINFO * phpi, LPVOID pv, BOOL * pfReleaseHint)
{
    LPSETNAMEOFINFO psnoi = (LPSETNAMEOFINFO) pv;

    if (phpi->psb)
        phpi->psb->SetStatusMessage(IDS_RENAMING, FtpPidl_GetLastItemDisplayName(psnoi->pidlOld));

    // Remember, FTP filenames are always in the ANSI character set
    return FtpRenameFilePidlWrap(hint, TRUE, psnoi->pidlOld, psnoi->pidlNew);
}


BOOL CFtpDir::_DoesItemExist(HWND hwnd, CFtpFolder * pff, LPCITEMIDLIST pidl)
{
    FTP_FIND_DATA wfd;
    HRESULT hr = GetFindData(hwnd, FtpPidl_GetLastItemWireName(pidl), &wfd, pff);

    return ((S_OK == hr) ? TRUE : FALSE);
}


BOOL CFtpDir::_ConfirmReplaceWithRename(HWND hwnd)
{
    TCHAR szTitle[MAX_PATH];
    TCHAR szMessage[MAX_PATH];

    EVAL(LoadString(HINST_THISDLL, IDS_FTPERR_TITLE, szTitle, ARRAYSIZE(szTitle)));
    EVAL(LoadString(HINST_THISDLL, IDS_FTPERR_RENAME_REPLACE, szMessage, ARRAYSIZE(szMessage)));

    return ((IDYES == MessageBox(hwnd, szMessage, szTitle, (MB_ICONQUESTION | MB_YESNO))) ? TRUE : FALSE);
}


HRESULT CFtpDir::SetNameOf(CFtpFolder * pff, HWND hwndOwner, LPCITEMIDLIST pidl,
           LPCWSTR pwzName, DWORD dwReserved, LPITEMIDLIST *ppidlOut)
{
    HRESULT hr = S_OK;
    SETNAMEOFINFO snoi;
    CWireEncoding cWireEncoding;

    ASSERT(pff);

    if (!pwzName)
        return E_FAIL;

    snoi.pidlOld = pidl;
    cWireEncoding.ChangeFtpItemIDName(NULL, pidl, pwzName, IsUTF8Supported(), (LPITEMIDLIST *) &snoi.pidlNew);

    if (snoi.pidlNew)
    {
#ifdef FEATURE_REPLACE_IN_RENAME
        // Disable this feature because we don't ever do the delete and there is no
        // way for us to have wininet do the delete for us.

        // Does it already exist?  We don't care if we don't have an hwnd because
        // we can't ask the user to replace so we will just go ahead.
        if (hwndOwner && _DoesItemExist(hwndOwner, pff, snoi.pidlNew))
        {
            // Yes, so let's make sure it's OK with the user to replace it.
            hr = (_ConfirmReplaceWithRename(hwndOwner) ? S_OK : HRESULT_FROM_WIN32(ERROR_CANCELLED));
            bugbug; // Delete the dest file so we will succeed with the rename.
        }
#endif FEATURE_REPLACE_IN_RENAME

        if (S_OK == hr)
        {
            hr = WithHint(NULL, hwndOwner, _SetNameOfCB, (LPVOID) &snoi, NULL, pff);
            if (SUCCEEDED(hr))  // Will fail if use didn't have permission to rename
            {
                // WARNING: The date/time stamp on the server may be different than what we give to SHChangeNotify()
                //          but this is probably reasonable for perf reasons.
                FtpChangeNotify(hwndOwner, FtpPidl_DirChoose(pidl, SHCNE_RENAMEFOLDER, SHCNE_RENAMEITEM), pff, this, pidl, snoi.pidlNew, TRUE);

                if (ppidlOut)
                    *ppidlOut = ILClone(snoi.pidlNew);
            }
        }

        ILFree((LPITEMIDLIST) snoi.pidlNew);
    }

    return hr;
}


LPCITEMIDLIST CFtpDir::GetPidlFromWireName(LPCWIRESTR pwWireName)
{
    LPITEMIDLIST pidlToFind = NULL;
    LPITEMIDLIST pidlTemp;
    WCHAR wzDisplayName[MAX_PATH];
    
    // This isn't valid because the code page could be wrong, but we don't care
    // because it's not used in the search for the pidl, the pwWireName is.
    SHAnsiToUnicode(pwWireName, wzDisplayName, ARRAYSIZE(wzDisplayName));
    if (m_pflHfpl && EVAL(SUCCEEDED(FtpItemID_CreateFake(wzDisplayName, pwWireName, FALSE, FALSE, FALSE, &pidlTemp))))
    {
        // PERF: log 2 (sizeof(m_pflHfpl))
        pidlToFind = m_pflHfpl->FindPidl(pidlTemp, FALSE);
        // We will try again and this time allow for the case to not match
        if (!pidlToFind)

⌨️ 快捷键说明

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