Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

239 lines
7.9 KiB

  1. /*****************************************************************************
  2. *
  3. * ftpresp.cpp - Parsing FTP responses
  4. *
  5. *****************************************************************************/
  6. #include "priv.h"
  7. /*****************************************************************************\
  8. FUNCTION: FindEndOfStrOrLine
  9. DESCRIPTION:
  10. Find the end of the line ('\n') or the end of the string ('\0').
  11. \*****************************************************************************/
  12. LPWIRESTR FindEndOfStrOrLine(LPWIRESTR pszString)
  13. {
  14. while (*pszString != '\0')
  15. {
  16. if (('\n' == pszString[0]))
  17. {
  18. while (('\n' == pszString[0]))
  19. pszString++;
  20. break;
  21. }
  22. pszString++;
  23. }
  24. return pszString;
  25. }
  26. /*****************************************************************************\
  27. FUNCTION: FindFirstMajorResponse
  28. DESCRIPTION:
  29. \*****************************************************************************/
  30. LPWIRESTR FindFirstMajorResponse(LPWIRESTR pszResponse)
  31. {
  32. while ((pszResponse[0]) && ('-' != pszResponse[3]))
  33. pszResponse = FindEndOfStrOrLine(pszResponse);
  34. return pszResponse;
  35. }
  36. /*****************************************************************************\
  37. FUNCTION: GetNextResponseSection
  38. DESCRIPTION:
  39. \*****************************************************************************/
  40. LPWIRESTR GetNextResponseSection(LPWIRESTR pszCompleteResponse, LPWIRESTR * ppszResponseStart)
  41. {
  42. LPWIRESTR pszNextResponse = NULL;
  43. // There may be a few minor responses. Skip over them...
  44. pszCompleteResponse = FindFirstMajorResponse(pszCompleteResponse);
  45. // Were we never able to fine a major response?
  46. if (!pszCompleteResponse[0])
  47. return NULL; // No, so return failure.
  48. // We are off to find the next major response.
  49. // We should be looking at a response code.
  50. ASSERT('-' == pszCompleteResponse[3]);
  51. // Slop saves us here
  52. // Extended response. Copy until we see the match.
  53. // As we copy, we also clean up the lines, removing
  54. // the random punctuation servers prepend to continuations.
  55. //
  56. // wu-ftp prepends the extended response code to each line:
  57. //
  58. // 230-Welcome to ftp.foo.com. Please read the rules
  59. // 230-and regulations in the file RULES.
  60. // 230 Guest login ok, access restrictions apply.
  61. //
  62. // Microsoft Internet Information Server prepends a space:
  63. //
  64. // 230-This is ftp.microsoft.com. See the index.txt file
  65. // in the root directory for more information.
  66. // 230 Anonymous user logged in as anonymous.
  67. //
  68. WIRECHAR szResponseNumber[5]; // example: "230-"
  69. WIRECHAR szResponseEnd[5]; // example: "230 "
  70. StrCpyNA(szResponseNumber, pszCompleteResponse, ARRAYSIZE(szResponseNumber));
  71. ASSERT(4 == lstrlenA(szResponseNumber));
  72. StrCpyNA(szResponseEnd, szResponseNumber, ARRAYSIZE(szResponseEnd));
  73. szResponseEnd[3] = ' ';
  74. pszNextResponse = pszCompleteResponse;
  75. *ppszResponseStart = pszCompleteResponse;
  76. do
  77. {
  78. // Skip past the header.
  79. if (!StrCmpNA(szResponseNumber, pszNextResponse, 4))
  80. pszNextResponse += 4; // wu-ftp
  81. else if ((pszNextResponse[0] == ' ') && (!StrCmpNA(szResponseNumber, &pszNextResponse[1], 4)))
  82. pszNextResponse += 5; // ftp.microsoft.com
  83. else if (pszNextResponse[0] == ' ')
  84. pszNextResponse++; // IIS
  85. // Skip the rest of the line.
  86. pszNextResponse = FindEndOfStrOrLine(pszNextResponse);
  87. }
  88. while (pszNextResponse[0] && StrCmpNA(pszNextResponse, szResponseEnd, 4));
  89. /* Now gobble the trailer */
  90. if ('\0' == pszNextResponse[0])
  91. pszNextResponse = NULL; // We are at the end.
  92. return pszNextResponse;
  93. }
  94. /*****************************************************************************\
  95. FUNCTION: StripResponseHeaders
  96. DESCRIPTION:
  97. \*****************************************************************************/
  98. void StripResponseHeaders(LPWIRESTR pszResponse)
  99. {
  100. // We should be looking at a response code.
  101. if ((3 < lstrlenA(pszResponse)) && (pszResponse[3] == '-'))
  102. {
  103. LPWIRESTR pszIterator = pszResponse;
  104. WIRECHAR szResponseNumber[5]; // example: "230-"
  105. WIRECHAR szResponseEnd[5]; // example: "230 "
  106. BOOL fFirstPass = TRUE;
  107. StrCpyNA(szResponseNumber, pszResponse, ARRAYSIZE(szResponseNumber));
  108. ASSERT(4 == lstrlenA(szResponseNumber));
  109. StrCpyNA(szResponseEnd, szResponseNumber, ARRAYSIZE(szResponseEnd));
  110. szResponseEnd[3] = ' ';
  111. do
  112. {
  113. // Skip past the header.
  114. if (!StrCmpNA(szResponseNumber, pszIterator, 4))
  115. RemoveCharsFromStringA(pszIterator, 3); // wu-ftp
  116. else if ((pszIterator[0] == ' ') && (!StrCmpNA(szResponseNumber, &pszIterator[1], 4)))
  117. RemoveCharsFromStringA(pszIterator, 4); // ftp.microsoft.com
  118. else if (pszIterator[0] == ' ')
  119. NULL; // IIS
  120. if (fFirstPass)
  121. {
  122. fFirstPass = FALSE;
  123. RemoveCharsFromStringA(pszIterator, 1); // IIS
  124. }
  125. else
  126. pszIterator[0] = ' '; // Make that new line a space.
  127. // Skip the rest of the line.
  128. pszIterator = FindEndOfStrOrLine(pszIterator);
  129. }
  130. while (pszIterator[0] && StrCmpNA(pszIterator, szResponseEnd, 4));
  131. RemoveCharsFromStringA(pszIterator, 4); // Now gobble the trailer
  132. }
  133. }
  134. /*****************************************************************************\
  135. FUNCTION: GetMOTDMessage
  136. DESCRIPTION:
  137. \*****************************************************************************/
  138. LPWIRESTR GetMOTDMessage(LPWIRESTR pwResponse, DWORD cchResponse)
  139. {
  140. LPWIRESTR pszMOTD = NULL;
  141. LPWIRESTR pszLast = &pwResponse[lstrlenA(pwResponse)];
  142. LPWIRESTR pszNext = pwResponse;
  143. LPWIRESTR pszEnd = NULL;
  144. while (pszNext = GetNextResponseSection(pszNext, &pszLast))
  145. pszEnd = pszNext;
  146. if (pszEnd)
  147. pszEnd[0] = '\0'; // Terminate it so we don't get the minor responses after our response.
  148. pszMOTD = (LPWIRESTR) GlobalAlloc(GPTR, (lstrlenA(pszLast) + 1) * sizeof(WIRECHAR));
  149. if (pszMOTD)
  150. {
  151. StrCpyA(pszMOTD, pszLast);
  152. StripResponseHeaders(pszMOTD);
  153. }
  154. return pszMOTD;
  155. }
  156. /*****************************************************************************\
  157. FUNCTION: GetFtpResponse
  158. DESCRIPTION:
  159. Get the MOTD from the Response
  160. \*****************************************************************************/
  161. CFtpGlob * GetFtpResponse(CWireEncoding * pwe)
  162. {
  163. CFtpGlob * pfg = NULL;
  164. DWORD cchResponse = 0;
  165. LPWIRESTR pwWireResponse;
  166. DWORD dwError;
  167. InternetGetLastResponseInfoWrap(TRUE, &dwError, NULL, &cchResponse);
  168. cchResponse++; /* +1 for the terminating 0 */
  169. pwWireResponse = (LPWIRESTR)LocalAlloc(LPTR, cchResponse * sizeof(WIRECHAR));
  170. if (pwWireResponse)
  171. {
  172. if (SUCCEEDED(InternetGetLastResponseInfoWrap(TRUE, &dwError, pwWireResponse, &cchResponse)))
  173. {
  174. LPWIRESTR pwMOTD = GetMOTDMessage(pwWireResponse, cchResponse);
  175. if (pwMOTD)
  176. {
  177. LPWSTR pwzDisplayMOTD;
  178. DWORD cchSize = (lstrlenA(pwMOTD) + 1);
  179. pwzDisplayMOTD = (LPWSTR)GlobalAlloc(LPTR, cchSize * sizeof(WCHAR));
  180. if (pwzDisplayMOTD)
  181. {
  182. pwe->WireBytesToUnicode(NULL, pwMOTD, WIREENC_IMPROVE_ACCURACY, pwzDisplayMOTD, cchSize);
  183. pfg = CFtpGlob_CreateStr(pwzDisplayMOTD);
  184. if (!(pfg))
  185. GlobalFree(pwzDisplayMOTD); // Couldn't track message
  186. }
  187. GlobalFree(pwMOTD);
  188. }
  189. }
  190. LocalFree(pwWireResponse);
  191. }
  192. return pfg;
  193. }