windows-nt/Source/XPSP1/NT/shell/ext/ftp/ftpresp.cpp
2020-09-26 16:20:57 +08:00

240 lines
7.9 KiB
C++

/*****************************************************************************
*
* ftpresp.cpp - Parsing FTP responses
*
*****************************************************************************/
#include "priv.h"
/*****************************************************************************\
FUNCTION: FindEndOfStrOrLine
DESCRIPTION:
Find the end of the line ('\n') or the end of the string ('\0').
\*****************************************************************************/
LPWIRESTR FindEndOfStrOrLine(LPWIRESTR pszString)
{
while (*pszString != '\0')
{
if (('\n' == pszString[0]))
{
while (('\n' == pszString[0]))
pszString++;
break;
}
pszString++;
}
return pszString;
}
/*****************************************************************************\
FUNCTION: FindFirstMajorResponse
DESCRIPTION:
\*****************************************************************************/
LPWIRESTR FindFirstMajorResponse(LPWIRESTR pszResponse)
{
while ((pszResponse[0]) && ('-' != pszResponse[3]))
pszResponse = FindEndOfStrOrLine(pszResponse);
return pszResponse;
}
/*****************************************************************************\
FUNCTION: GetNextResponseSection
DESCRIPTION:
\*****************************************************************************/
LPWIRESTR GetNextResponseSection(LPWIRESTR pszCompleteResponse, LPWIRESTR * ppszResponseStart)
{
LPWIRESTR pszNextResponse = NULL;
// There may be a few minor responses. Skip over them...
pszCompleteResponse = FindFirstMajorResponse(pszCompleteResponse);
// Were we never able to fine a major response?
if (!pszCompleteResponse[0])
return NULL; // No, so return failure.
// We are off to find the next major response.
// We should be looking at a response code.
ASSERT('-' == pszCompleteResponse[3]);
// Slop saves us here
// Extended response. Copy until we see the match.
// As we copy, we also clean up the lines, removing
// the random punctuation servers prepend to continuations.
//
// wu-ftp prepends the extended response code to each line:
//
// 230-Welcome to ftp.foo.com. Please read the rules
// 230-and regulations in the file RULES.
// 230 Guest login ok, access restrictions apply.
//
// Microsoft Internet Information Server prepends a space:
//
// 230-This is ftp.microsoft.com. See the index.txt file
// in the root directory for more information.
// 230 Anonymous user logged in as anonymous.
//
WIRECHAR szResponseNumber[5]; // example: "230-"
WIRECHAR szResponseEnd[5]; // example: "230 "
StrCpyNA(szResponseNumber, pszCompleteResponse, ARRAYSIZE(szResponseNumber));
ASSERT(4 == lstrlenA(szResponseNumber));
StrCpyNA(szResponseEnd, szResponseNumber, ARRAYSIZE(szResponseEnd));
szResponseEnd[3] = ' ';
pszNextResponse = pszCompleteResponse;
*ppszResponseStart = pszCompleteResponse;
do
{
// Skip past the header.
if (!StrCmpNA(szResponseNumber, pszNextResponse, 4))
pszNextResponse += 4; // wu-ftp
else if ((pszNextResponse[0] == ' ') && (!StrCmpNA(szResponseNumber, &pszNextResponse[1], 4)))
pszNextResponse += 5; // ftp.microsoft.com
else if (pszNextResponse[0] == ' ')
pszNextResponse++; // IIS
// Skip the rest of the line.
pszNextResponse = FindEndOfStrOrLine(pszNextResponse);
}
while (pszNextResponse[0] && StrCmpNA(pszNextResponse, szResponseEnd, 4));
/* Now gobble the trailer */
if ('\0' == pszNextResponse[0])
pszNextResponse = NULL; // We are at the end.
return pszNextResponse;
}
/*****************************************************************************\
FUNCTION: StripResponseHeaders
DESCRIPTION:
\*****************************************************************************/
void StripResponseHeaders(LPWIRESTR pszResponse)
{
// We should be looking at a response code.
if ((3 < lstrlenA(pszResponse)) && (pszResponse[3] == '-'))
{
LPWIRESTR pszIterator = pszResponse;
WIRECHAR szResponseNumber[5]; // example: "230-"
WIRECHAR szResponseEnd[5]; // example: "230 "
BOOL fFirstPass = TRUE;
StrCpyNA(szResponseNumber, pszResponse, ARRAYSIZE(szResponseNumber));
ASSERT(4 == lstrlenA(szResponseNumber));
StrCpyNA(szResponseEnd, szResponseNumber, ARRAYSIZE(szResponseEnd));
szResponseEnd[3] = ' ';
do
{
// Skip past the header.
if (!StrCmpNA(szResponseNumber, pszIterator, 4))
RemoveCharsFromStringA(pszIterator, 3); // wu-ftp
else if ((pszIterator[0] == ' ') && (!StrCmpNA(szResponseNumber, &pszIterator[1], 4)))
RemoveCharsFromStringA(pszIterator, 4); // ftp.microsoft.com
else if (pszIterator[0] == ' ')
NULL; // IIS
if (fFirstPass)
{
fFirstPass = FALSE;
RemoveCharsFromStringA(pszIterator, 1); // IIS
}
else
pszIterator[0] = ' '; // Make that new line a space.
// Skip the rest of the line.
pszIterator = FindEndOfStrOrLine(pszIterator);
}
while (pszIterator[0] && StrCmpNA(pszIterator, szResponseEnd, 4));
RemoveCharsFromStringA(pszIterator, 4); // Now gobble the trailer
}
}
/*****************************************************************************\
FUNCTION: GetMOTDMessage
DESCRIPTION:
\*****************************************************************************/
LPWIRESTR GetMOTDMessage(LPWIRESTR pwResponse, DWORD cchResponse)
{
LPWIRESTR pszMOTD = NULL;
LPWIRESTR pszLast = &pwResponse[lstrlenA(pwResponse)];
LPWIRESTR pszNext = pwResponse;
LPWIRESTR pszEnd = NULL;
while (pszNext = GetNextResponseSection(pszNext, &pszLast))
pszEnd = pszNext;
if (pszEnd)
pszEnd[0] = '\0'; // Terminate it so we don't get the minor responses after our response.
pszMOTD = (LPWIRESTR) GlobalAlloc(GPTR, (lstrlenA(pszLast) + 1) * sizeof(WIRECHAR));
if (pszMOTD)
{
StrCpyA(pszMOTD, pszLast);
StripResponseHeaders(pszMOTD);
}
return pszMOTD;
}
/*****************************************************************************\
FUNCTION: GetFtpResponse
DESCRIPTION:
Get the MOTD from the Response
\*****************************************************************************/
CFtpGlob * GetFtpResponse(CWireEncoding * pwe)
{
CFtpGlob * pfg = NULL;
DWORD cchResponse = 0;
LPWIRESTR pwWireResponse;
DWORD dwError;
InternetGetLastResponseInfoWrap(TRUE, &dwError, NULL, &cchResponse);
cchResponse++; /* +1 for the terminating 0 */
pwWireResponse = (LPWIRESTR)LocalAlloc(LPTR, cchResponse * sizeof(WIRECHAR));
if (pwWireResponse)
{
if (SUCCEEDED(InternetGetLastResponseInfoWrap(TRUE, &dwError, pwWireResponse, &cchResponse)))
{
LPWIRESTR pwMOTD = GetMOTDMessage(pwWireResponse, cchResponse);
if (pwMOTD)
{
LPWSTR pwzDisplayMOTD;
DWORD cchSize = (lstrlenA(pwMOTD) + 1);
pwzDisplayMOTD = (LPWSTR)GlobalAlloc(LPTR, cchSize * sizeof(WCHAR));
if (pwzDisplayMOTD)
{
pwe->WireBytesToUnicode(NULL, pwMOTD, WIREENC_IMPROVE_ACCURACY, pwzDisplayMOTD, cchSize);
pfg = CFtpGlob_CreateStr(pwzDisplayMOTD);
if (!(pfg))
GlobalFree(pwzDisplayMOTD); // Couldn't track message
}
GlobalFree(pwMOTD);
}
}
LocalFree(pwWireResponse);
}
return pfg;
}