📄 ftppidl.cpp
字号:
\*****************************************************************************/
HRESULT CreateFtpPidlFromUrlEx(LPCTSTR pszUrl, CWireEncoding * pwe, ULONG *pcchEaten, LPITEMIDLIST * ppidl, IMalloc * pm, BOOL fHidePassword, BOOL fIsTypeKnown, BOOL fIsDir)
{
URL_COMPONENTS urlComps = {0};
HRESULT hr = E_FAIL;
// URL = "ftp://<UserName>:<Password>@<HostName>:<PortNum>/Dir1/Dir2/Dir3/file.txt[;Type=[a|b|d]]"
TCHAR szServer[INTERNET_MAX_HOST_NAME_LENGTH];
TCHAR szUrlPath[MAX_URL_STRING];
TCHAR szExtraInfo[MAX_PATH]; // Includes Port Number and download type (ASCII, Binary, Detect)
TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH];
TCHAR szPassword[INTERNET_MAX_PASSWORD_LENGTH];
*ppidl = 0;
urlComps.dwStructSize = sizeof(urlComps);
urlComps.lpszHostName = szServer;
urlComps.dwHostNameLength = ARRAYSIZE(szServer);
urlComps.lpszUrlPath = szUrlPath;
urlComps.dwUrlPathLength = ARRAYSIZE(szUrlPath);
urlComps.lpszUserName = szUserName;
urlComps.dwUserNameLength = ARRAYSIZE(szUserName);
urlComps.lpszPassword = szPassword;
urlComps.dwPasswordLength = ARRAYSIZE(szPassword);
urlComps.lpszExtraInfo = szExtraInfo;
urlComps.dwExtraInfoLength = ARRAYSIZE(szExtraInfo);
BOOL fResult = InternetCrackUrl(pszUrl, 0, ICU_DECODE, &urlComps);
if (fResult && (INTERNET_SCHEME_FTP == urlComps.nScheme))
{
LPITEMIDLIST pidl;
DWORD dwDownloadType = 0; // Indicate that it hasn't yet been specified.
BOOL fASCII;
ASSERT(INTERNET_SCHEME_FTP == urlComps.nScheme);
// NOTE:
// If the user is trying to give an NT UserName/DomainName pair, a bug will be encountered.
// Url in AddressBand="ftp://DomainName\UserName:Password@ServerName/"
// Url passed to us="ftp://DomainName/UserName:Password@ServerName/"
// We need to detect this case and fix it because this will cause "DomainName" to become
// the server name and the rest will become the UrlPath.
// ASSERT(!StrChr(szUrlPath, TEXT(':')) && !StrChr(szUrlPath, TEXT('@')));
if (S_OK == UrlRemoveDownloadType(szUrlPath, NULL, &fASCII))
{
if (fASCII)
dwDownloadType = (IDVALID_DLTYPE | IDVALID_DL_ASCII);
else
dwDownloadType = IDVALID_DLTYPE;
}
if (!szServer[0])
{
TraceMsg(TF_FTPURL_UTILS, "CreateFtpPidlFromUrl() failed because szServer=%s", szServer);
hr = E_FAIL; // Bad URL so fail.
}
else
{
//TraceMsg(TF_FTPURL_UTILS, "CreateFtpPidlFromUrl() szServer=%s, szUrlPath=%s, szUserName=%s, szPassword=%s", szServer, szUrlPath, szUserName, szPassword);
hr = FtpServerID_Create(szServer, szUserName, szPassword, dwDownloadType, urlComps.nPort, &pidl, pm, fHidePassword);
if (EVAL(SUCCEEDED(hr)))
{
ASSERT(IsValidPIDL(pidl));
if (szUrlPath[0] && StrCmp(szUrlPath, SZ_URL_SLASH))
{
LPITEMIDLIST pidlSub;
hr = CreateFtpPidlFromDisplayPath(szUrlPath, pwe, pcchEaten, &pidlSub, fIsTypeKnown, fIsDir);
if (EVAL(SUCCEEDED(hr)))
{
// If the URL path ends in a slash, then it's safe to assume that web-based FTP
// is looking for a directory. Otherwise, we choke during requests through Netscape
// proxies when the GET is redirected by the proxy to include the slash.
if (IsWebBasedFtpEnabled() && szUrlPath[lstrlen(szUrlPath)-1] == TEXT(CH_URL_URL_SLASHA))
{
LPCITEMIDLIST pidlLast = ILGetLastID(pidlSub);
if (pidlLast)
FtpItemID_SetCompatFlags(pidlLast, FtpItemID_GetCompatFlags(pidlLast) | COMPAT_WEBBASEDDIR);
}
*ppidl = ILCombine(pidl, pidlSub);
if (szExtraInfo[0])
{
LPITEMIDLIST pidlFragment;
WIRECHAR wFragment[MAX_PATH];
// The code page is just whatever the user is using but oh well, I don't
// care about fragments.
SHUnicodeToAnsi(szExtraInfo, wFragment, ARRAYSIZE(wFragment));
// There is a fragment, so we need to add it.
hr = FtpItemID_CreateFake(szExtraInfo, wFragment, TRUE, FALSE, TRUE, &pidlFragment);
if (EVAL(SUCCEEDED(hr)))
{
LPITEMIDLIST pidlPrevious = *ppidl;
*ppidl = ILCombine(pidlPrevious, pidlFragment);
ILFree(pidlPrevious);
ILFree(pidlFragment);
}
}
hr = *ppidl ? S_OK : E_OUTOFMEMORY;
ILFree(pidlSub);
}
ILFree(pidl);
}
else
*ppidl = pidl;
if (SUCCEEDED(hr))
{
ASSERT(IsValidPIDL(*ppidl));
if (pcchEaten)
*pcchEaten = lstrlen(pszUrl); // TODO: Someday we can do this recursively.
}
}
}
}
else
TraceMsg(TF_FTPURL_UTILS, "CreateFtpPidlFromUrl() failed InternetCrackUrl() because pszUrl=%s, fResult=%d, urlComps.nScheme=%d", pszUrl, fResult, urlComps.nScheme);
//TraceMsg(TF_FTPURL_UTILS, "CreateFtpPidlFromUrl() is returning, hr=%#08lx", hr);
return hr;
}
/*****************************************************************************\
FUNCTION: Win32FindDataFromPidl
DESCRIPTION:
Fill in the WIN32_FIND_DATA data structure from the info in the pidl.
\*****************************************************************************/
HRESULT Win32FindDataFromPidl(LPCITEMIDLIST pidl, LPWIN32_FIND_DATAW pwfd, BOOL fFullPath, BOOL fInDisplayFormat)
{
HRESULT hr = E_INVALIDARG;
LPCITEMIDLIST pidlLast = ILGetLastID(pidl);
ASSERT(pwfd);
if (!EVAL(FtpPidl_IsValid(pidl)))
return E_INVALIDARG;
// I don't want to lie when I pass out File Size and Date info.
if ((IDVALID_FILESIZE | IDVALID_MOD_DATE) & FtpItemID_GetTypeID(pidlLast))
{
pwfd->nFileSizeLow = FtpItemID_GetFileSizeLo(pidlLast);
pwfd->nFileSizeHigh = FtpItemID_GetFileSizeHi(pidlLast);
pwfd->dwFileAttributes = FtpItemID_GetAttributes(pidlLast);
// See the notes in priv.h on how time works.
pwfd->ftCreationTime = FtpPidl_GetFTPFileTime(pidlLast);
pwfd->ftLastWriteTime = pwfd->ftCreationTime;
pwfd->ftLastAccessTime = pwfd->ftCreationTime;
if (fFullPath)
{
if (fInDisplayFormat)
hr = GetDisplayPathFromPidl(pidl, pwfd->cFileName, ARRAYSIZE(pwfd->cFileName), FALSE);
else
hr = GetWirePathFromPidl(pidl, (LPWIRESTR)pwfd->cFileName, ARRAYSIZE(pwfd->cFileName), FALSE);
}
else
{
hr = S_OK;
if (fInDisplayFormat)
StrCpyNW(pwfd->cFileName, FtpPidl_GetLastFileDisplayName(pidl), ARRAYSIZE(pwfd->cFileName));
else
StrCpyNA((LPWIRESTR)pwfd->cFileName, FtpPidl_GetLastItemWireName(pidl), ARRAYSIZE(pwfd->cFileName));
}
}
return hr;
}
/****************************************************\
FTP Server ItemIDs
\****************************************************/
/****************************************************\
FTP PIDL Cooking functions
\****************************************************/
/*****************************************************************************\
DATA STRUCTURE: FTPIDLIST
DESCRIPTION:
What our private IDLIST looks like for a file, a dir, or a fragment.
The bytes sent to an ftp server or received from an FTP server are
wire bytes (could be UTF-8 or DBCS/MBCS) encoded. We also store
a unicode version that has already been converted after trying to guess
the code page.
Note that the use of any TCHAR inside an IDLIST is COMPLETELY WRONG!
IDLISTs can be saved in a file and reloaded later. If it were saved
by an ANSI version of the shell extension but loaded by a UNICODE
version, things would turn ugly real fast.
\*****************************************************************************/
/*****************************************************************************\
FTPSERVERIDLIST structure
A typical full pidl looks like this:
<Not Our ItemID> [Our ItemID]
<The Internet>\[server,username,password,port#,downloadtype]\[subdir]\...\[file]
The <The Internet> part is whatever the shell gives us in our
CFtpFolder::_Initialize, telling us where in the namespace
we are rooted.
We are concerned only with the parts after the <The Internet> root,
the offset to which is remembered in the CFtpFolder class
in m_ibPidlRoot. Ways of accessing various bits of
information related to our full pidl are provided by our
CFtpFolder implementation, qv.
The first FTP IDList entry describes the server. The remaining
entries describe objects (files or folders) on the server.
\*****************************************************************************/
typedef struct tagFTPSERVERIDLIST
{
DWORD dwIDType; // Server ItemID or Dir ItemID? Which Bits are valid?
DWORD dwVersion; // version
SESSIONKEY sessionKey; // Session Key
DWORD dwPasswordCookie; // Password Cookie
DWORD dwReserved1; // for future use
DWORD dwReserved2; // for future use
DWORD dwReserved3; // for future use
DWORD dwPortNumber; // Port Number on server
DWORD cchServerSize; // StrLen of szServer
CHAR szServer[INTERNET_MAX_HOST_NAME_LENGTH]; // Server
DWORD cchUserNameSize; // StrLen of szUserName
CHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH]; // User Name for Login
DWORD cchPasswordSize; // StrLen of szPassword
CHAR szPassword[INTERNET_MAX_PASSWORD_LENGTH]; // Password for Login
} FTPSERVERIDLIST;
typedef UNALIGNED FTPSERVERIDLIST * LPFTPSERVERIDLIST;
LPFTPSERVERIDLIST FtpServerID_GetData(LPCITEMIDLIST pidl)
{
LPFTPSERVERIDLIST pFtpServerItemId = (LPFTPSERVERIDLIST) ProtocolIdlInnerData(pidl);
if (!FtpPidl_IsValid(pidl) ||
!IS_VALID_SERVER_ITEMID(pFtpServerItemId->dwIDType)) // If any other bits are sit, it's invalid.
pFtpServerItemId = NULL;
return pFtpServerItemId;
}
LPFTPSERVERIDLIST FtpServerID_GetDataSafe(LPCITEMIDLIST pidl)
{
LPFTPSERVERIDLIST pFtpServerItemId = NULL;
if (EVAL(pidl) && !ILIsEmpty(pidl))
pFtpServerItemId = (LPFTPSERVERIDLIST) ProtocolIdlInnerData(pidl);
return pFtpServerItemId;
}
BOOL FtpID_IsServerItemID(LPCITEMIDLIST pidl)
{
LPFTPSERVERIDLIST pFtpServerItemID = FtpServerID_GetDataSafe(pidl);
BOOL fIsServerItemID = FALSE;
if (pFtpServerItemID && IS_VALID_SERVER_ITEMID(pFtpServerItemID->dwIDType))
fIsServerItemID = TRUE;
return fIsServerItemID;
}
LPCITEMIDLIST FtpID_GetLastIDReferense(LPCITEMIDLIST pidl)
{
LPCITEMIDLIST pidlCurrent = pidl;
LPCITEMIDLIST pidlNext = pidl;
if (!pidl || ILIsEmpty(pidl))
return pidl;
for (; !ILIsEmpty(pidlNext); pidl = _ILNext(pidl))
{
pidlCurrent = pidlNext;
pidlNext = _ILNext(pidlNext);
}
return pidlCurrent;
}
CCookieList * g_pCookieList = NULL;
CCookieList * GetCookieList(void)
{
ENTERCRITICAL;
if (!g_pCookieList)
g_pCookieList = new CCookieList();
ASSERT(g_pCookieList);
LEAVECRITICAL;
return g_pCookieList;
}
SESSIONKEY g_SessionKey = {-1, -1};
HRESULT PurgeSessionKey(void)
{
GetSystemTimeAsFileTime(&g_SessionKey);
return S_OK;
}
SESSIONKEY GetSessionKey(void)
{
if (-1 == g_SessionKey.dwHighDateTime)
PurgeSessionKey();
return g_SessionKey;
}
BOOL AreSessionKeysEqual(SESSIONKEY sk1, SESSIONKEY sk2)
{
if ((sk1.dwHighDateTime == sk2.dwHighDateTime) &&
(sk1.dwLowDateTime == sk2.dwLowDateTime))
{
return TRUE;
}
return FALSE;
}
// This is used in order to make sure Alpha machines don't get DWORD mis-aligned.
#define LENGTH_AFTER_ALIGN(nLen, nAlignSize) (((nLen) % (nAlignSize)) ? ((nLen) + ((nAlignSize) - ((nLen) % (nAlignSize)))) : (nLen))
/****************************************************\
FUNCTION: FtpServerID_Create
DESCRIPTION:
Create a Ftp Server ItemID and fill it in.
\****************************************************/
HRESULT FtpServerID_Create(LPCTSTR pszServer, LPCTSTR pszUserName, LPCTSTR pszPassword,
DWORD dwFlags, INTERNET_PORT ipPortNum, LPITEMIDLIST * ppidl, IMalloc *pm, BOOL fHidePassword)
{
HRESULT hr;
DWORD cb;
LPITEMIDLIST pidl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -