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

📄 ftpfoldr.cpp

📁 很好用的ftp源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
                {
                    CFtpSite * pfs;
            
                    hr = SiteCache_PidlLookup(pidlBaseDir, TRUE, m_pm, &pfs);
                    if (EVAL(SUCCEEDED(hr)))
                    {
                        LPCWIRESTR pwLastDirName;

                        // If we are using a hidden password, then ::GetDisplayNameOf() hands out
                        // these "ftp://user@server/dir/" URLs and the password is hidden.  If
                        // :: ParseDisplayName() is given one of these URLs and we are currently in
                        // that server w/that user name, then :: ParseDisplayNameOf() needs to hand
                        // out a pidl with the correct hidden password cookie.
                        //
                        // Is pidlNav the same as GetPublicRootPidlReference() except pidlNav doesn't
                        // have a password.  The same means that the servers match, and the user names
                        // match.
                        EVAL(SUCCEEDED(pfs->UpdateHiddenPassword(pidlBaseDir)));

                        // This is sneaky because pwLastDirName will point into them itemID
                        // that will be removed.  The memory won't really be removed, it will
                        // just have the size set to zero.
                        pwLastDirName = FtpPidl_GetLastItemWireName(pidlBaseDir);

                        ILRemoveLastID(pidlBaseDir);
                        pfs->GetFtpDir(pidlBaseDir, &pfd);

                        if (pfd)
                        {
                            LPITEMIDLIST pidlFromCache = (LPITEMIDLIST) pfd->GetPidlFromWireName(pwLastDirName);
                            if (pidlFromCache)
                            {
                                // It was found, this means we were probably in ftp://serverX/Dir1/
                                // and the user entered something from that directory or another directory
                                // taht we have alread displayed to the user and it's in our cache.
                                *ppidl = ILCombine(pidlBaseDir, pidlFromCache);
                                ILFree(pidlFromCache);
                                hr = S_OK;
                            }
                            else
                            {
                                // There is one last thing we need to try, we need to detect if:
                                // 1) the URL has an URL path, and 
                                // 2) the last item in the path doesn't have an extension and doesn't
                                //    end in a slash ('/') to indicate it's a directory.
                                // If this case is true, we then need to find out if it is a directory
                                // or file by hitting the server.  This is needed because by the time
                                // we bind, it's too late to fall back to the other thing (IEnumIDList).
                                // The one thing we might need to be careful about is AutoComplete because
                                // they may call :: ParseDisplayName() for every character a user types.
                                // This won't be so bad because it's on a background thread, asynch, and
                                // the first enum within a segment will cause the cache to be populated
                                // within a that segment so subsequent enums will be fast.  The problem
                                // it that it's not uncommon for users to enter between 2 and 5 segments,
                                // and there would be 1 enum per segment.
                                hr = _ForPopulateAndEnum(pfd, pidlBaseDir, pszDisplayName, pwLastDirName, ppidl);
                            }


                            pfd->Release();
                        }
                        else
                            hr = E_FAIL;

                        pfs->Release();
                    }
                    else
                        hr = E_FAIL;
                }
                else
                    hr = E_FAIL;

                ILFree(pidlBaseDir);
            }
        }
        else
        {
            //    Create a new enumeration object for the caller.
            // PERF: log 2 (sizeof(m_pflHfpl))
            *ppidl = (LPITEMIDLIST) pfd->GetPidlFromDisplayName(pszDisplayName);
            if (*ppidl)
            {
                hr = S_OK;
            }
            else
            {
                // If we got here, the cache for this directory is populated.
                // So if the name doesn't match, then either:
                // 1) it doesn't exist,
                // 2) the cache is out of date, or
                // 3) it's multilevel, (like "dir1\dir2\dir3") or
                // 4) It's a weird parsing token that our parent parse should have remoted, like "..", ".", "\", etc.
                // We will assome our parent parse takes care of #4, and #2 isn't true.

                // Is this multilevel? (Case #3)
                if (!StrChr(pszDisplayName, TEXT('/')))
                {
                    // No, so reject it and don't let our caller blindly accept it.
                    hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
                }
            }

            pfd->Release();
        }
    }

    return hr;
}


HRESULT CFtpFolder::_GetBindCtx(IBindCtx ** ppbc)
{
    HRESULT hr = CreateBindCtx(NULL, ppbc);

    if (SUCCEEDED(hr))	// Can fail with out of memory
    {
        hr = (*ppbc)->RegisterObjectParam(STR_SKIP_BINDING_CLSID, SAFECAST(this, IShellIcon *));    // We want IUnknown, not IShellIcon, but this is to disambigiuate.
    }

    return hr;
}


HRESULT CFtpFolder::_GetLegacyURL(LPCITEMIDLIST pidl, IBindCtx * pbc, LPTSTR pszUrl, DWORD cchSize)
{
    HRESULT hr = S_OK;
    LPITEMIDLIST pidlWithVRoot;

    // We now need to insert the virtual root path into the path section
    // of the URL because the old FTP support doesn't follow the correct
    // FTP URL spec that says that the virtual root needs to be left out
    // of the URL.
    hr = _ConvertPidlForRootedFix(pidl, &pidlWithVRoot);
    if (SUCCEEDED(hr))
    {
        WCHAR wzFrag[MAX_PATH];

        // SECURITY ISSUE: We need to get the URL w/password or it won't work, but
        //                 this will expose the password publicly.  We need a way for
        //                 the real FTP URL Pidl to hide the password.
        hr = UrlCreateFromPidlW(pidlWithVRoot, SHGDN_FORPARSING, pszUrl, cchSize, (ICU_ESCAPE | ICU_USERNAME), FALSE);
        if (ILGetHiddenStringW(pidl, IDLHID_URLFRAGMENT, wzFrag, ARRAYSIZE(wzFrag)))  // Add fragment if it exists.
            UrlCombineW(pszUrl, wzFrag, pszUrl, &cchSize, 0);

        ILFree(pidlWithVRoot);
    }

    return hr;
}


HRESULT CFtpFolder::_GetLegacyPidl(LPCITEMIDLIST pidl, LPITEMIDLIST * ppidlLegacy)
{
    IBindCtx * pbc = NULL;
    HRESULT hr = _GetBindCtx(&pbc);

    *ppidlLegacy = NULL;
    if (SUCCEEDED(hr))   // Can fail with out of memory.
    {
        WCHAR wzUrl[MAX_URL_STRING];

        hr = _GetLegacyURL(pidl, pbc, wzUrl, ARRAYSIZE(wzUrl));
        if (EVAL(SUCCEEDED(hr)))
        {
            TraceMsg(TF_FTPISF, "_BindToObject_OriginalFtpSupport() navigating to=%ls", wzUrl);
            hr = IEParseDisplayNameWithBCW(CP_ACP, wzUrl, pbc, ppidlLegacy);
        }

        pbc->Release();
    }

    return hr;
}


HRESULT CFtpFolder::_InitLegacyShellFolder(IShellFolder * psfLegacy, LPCITEMIDLIST pidlInit)
{
    IPersistFolder * ppf;
    HRESULT hr = psfLegacy->QueryInterface(IID_IPersistFolder, (void **) &ppf);

    if (SUCCEEDED(hr))
    {
        hr = ppf->Initialize(pidlInit);
        ppf->Release();
    }

    return hr;
}


HRESULT CFtpFolder::_INetBindToObject(LPCITEMIDLIST pidl, IBindCtx * pbc, REFIID riid, LPVOID * ppvObj)
{
    HRESULT hr = E_OUTOFMEMORY;

    LPITEMIDLIST pidlFirst = GetPublicPidlRootIDClone();
    if (pidlFirst)
    {
        IShellFolder * psfInternetSF;

        hr = IEBindToObject(pidlFirst, &psfInternetSF);
        if (EVAL(SUCCEEDED(hr)))
        {
            hr = _InitLegacyShellFolder(psfInternetSF, pidlFirst);
            if (SUCCEEDED(hr))
            {
                // Note the I use ILNext() in order to skip past the Desktop ItemID,
                // which is internal knowledge I should not have.
                hr = psfInternetSF->BindToObject(_ILNext(pidl), pbc, riid, ppvObj);
            }

            psfInternetSF->Release();
        }

        ILFree(pidlFirst);
    }

    return hr;
}



HRESULT CFtpFolder::_BindToObject_OriginalFtpSupport(LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvObj)
{
    LPBC pbc = NULL;
    HRESULT hr = CreateBindCtx(NULL, &pbc);
    
    if (EVAL(SUCCEEDED(hr)))
    {
        hr = pbc->RegisterObjectParam(STR_SKIP_BINDING_CLSID, SAFECAST(this, IShellIcon *));    // We want IUnknown, not IShellIcon, but this is to disambigiuate.
        if (EVAL(SUCCEEDED(hr)))
        {
            LPITEMIDLIST pidlLegacy;

            hr = _GetLegacyPidl(pidl, &pidlLegacy);
            if (EVAL(SUCCEEDED(hr)))
            {
                hr = _INetBindToObject(pidlLegacy, pbc, riid, ppvObj);
                ILFree(pidlLegacy);
            }
        }

        pbc->Release();
    }

    ASSERT_POINTER_MATCHES_HRESULT(*ppvObj, hr);
    return hr;
}


/*****************************************************************************\
    FUNCTION:   _IsValidPidlParameter

    DESCRIPTION:
        If this IShellFolder is rooted within our name space, then the pidl needs
    to be a valid relative pidl.  If we are rooted at the base of our name space,
    then it needs to be a full pidl.
\*****************************************************************************/
BOOL CFtpFolder::_IsValidPidlParameter(LPCITEMIDLIST pidl)
{
    BOOL fResult = TRUE;

    if (IsRoot())
        fResult = FtpPidl_IsValidFull(pidl);
    else
        fResult = FtpPidl_IsValidRelative(pidl);

    return fResult;
}


/*****************************************************************************\
    FUNCTION: IShellFolder::_BindToObject

    DESCRIPTION:
        We are now sure that we want to handle the support, so check what they
    want.
\*****************************************************************************/
HRESULT CFtpFolder::_BindToObject(LPCITEMIDLIST pidl, LPCITEMIDLIST pidlFull, IBindCtx * pbc, REFIID riid, LPVOID * ppvObj)
{
    HRESULT hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);   // Indicate we want the old functionality to kick in.

    if (IsEqualIID(riid, IID_IShellFolder) || IsEqualIID(riid, IID_IShellFolder2))
    {
        LPITEMIDLIST pidlTarget = ILCombine(GetPublicTargetPidlReference(), pidl);
        LPITEMIDLIST pidlRoot = (GetFolderPidl() ? ILCombine(GetFolderPidl(), pidl) : NULL);

        //  There's no point trying to verify that it's folders all
        //  the way down, because it's the caller's job not to combine
        //  pidls randomly.  Furthermore, they might not actually be marked
        //  as folders if we got them via ParseDisplayName.

        // NOTE: Binding will succeed even if the pidl isn't valid on the
        //       server.  In the future we may want to verify now so we
        //       don't hand out a IEnumIDList that won't work.  Currently,
        //       IEnumIDList will fail and cause a renavigation if it can
        //       connect to the server in a different way (different username
        //       password pair).  It would be better to do a redirect because
        //       the renavigation causes the bad entry in the navigation stack.
        //       We can't verify the item exists on the server if we have a WebProxy
        //       installed.

        hr = CFtpFolder_Create(pidlTarget, pidlRoot, GetPidlByteOffset(), riid, ppvObj);
        //TraceMsg(TF_FOLDER_SHRTCUTS, "CFtpFolder::_BindToObject() creating an FTP IShellFolder psf=%#08lx, pidlTarget=%#08lx, pidlRoot=%#08lx", *ppvObj, pidlTarget, pidlRoot);
        if (EVAL(SUCCEEDED(hr)))
        {
            IUnknown * punk = (IUnknown *) *ppvObj;
            IDelegateFolder * pdf;

            hr = punk->QueryInterface(IID_IDelegateFolder, (LPVOID *) &pdf);
            if (EVAL(SUCCEEDED(hr)))
            {
                if (EVAL(SUCCEEDED(hr)))
                    hr = pdf->SetItemAlloc(m_pm);
                pdf->Release();
            }
        }

        ILFree(pidlTarget);
        ILFree(pidlRoot);
        //TraceMsg(TF_FTPISF, "CFtpFolder::BindToObject() IID_IShellFolder hr=%#08lx", hr);
    }
    else if (IsEqualIID(riid, IID_IMoniker))
    {
        hr = _PidlToMoniker(pidlFull, (IMoniker **) ppvObj);
    }
    else if (IsEqualIID(riid, IID_CFtpFolder))
    {
        IShellFolder * psf;

        // Nothing like a little recursion to keep the code clean.
        // The fact that we use IID_IShellFolder guarantees the breaking
        // of the recursion.
        hr = BindToObject(pidl, pbc, IID_IShellFolder, (void **) &psf);
        if (EVAL(SUCCEEDED(hr)))
        {
            hr = psf->QueryInterface(riid, ppvObj);
            psf->Release();
        }
    }
    else
    {
        TraceMsg(TF_FTPISF, "CFtpFolder::BindToObject() unsupported interface hr=E_NOINTERFACE");
        *ppvObj = NULL;
        hr = E_NOINTERFACE;
    }

    return hr;
}


/*****************************************************************************\
     FUNCTION: _ConvertPidlForRootedFix
 
    DESCRIPTION:
        If an FTP URL has a login name, that login may root the user under a directory other than "/".
    The FTP URL spec (RFC 1738) says that URL paths need to be relative to the rooted directory.  For example:
    If UserA's rooted account is in \usr\GroupA\UserA and the url is:
    ftp://UserA:FooBar@server/test/file.txt, then the real path is \usr\GroupA\UserA\test\file.txt.
    The problem is that the old FTP code doesn't respect this and requires:
    ftp://UserA:FooBar@server/usr/GroupA/UserA/test/file.txt, so we fix that here.
 
    PARAMETERS:
        pidlBefore [IN]: This will be a public pidl to the item to navigate to.

⌨️ 快捷键说明

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