home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / INET.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-03  |  66.2 KB  |  2,726 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12. #include <afxtempl.h>
  13. #include <afxinet.h>
  14. #include "inetimpl.h"
  15.  
  16. #pragma warning(disable: 4706) // assignment within conditional
  17.  
  18. /////////////////////////////////////////////////////////////////////////////
  19. // non-localized useful strings
  20.  
  21. typedef struct tagServiceTable {
  22.     DWORD dwService;
  23.     LPCTSTR pstrIdentifier;
  24. } SvcTable;
  25.  
  26. static const TCHAR szURLftp[] = _T("ftp://");
  27. static const TCHAR szURLgopher[] = _T("gopher://");
  28. static const TCHAR szURLhttp[] = _T("http://");
  29.  
  30. const LPCTSTR CHttpConnection::szHtmlVerbs[] = {
  31.     _T("POST"),
  32.     _T("GET"),
  33.     _T("HEAD"),
  34.     _T("PUT"),
  35.     _T("LINK"),
  36.     _T("DELETE"),
  37.     _T("UNLINK"),
  38. };
  39.  
  40.  
  41. /////////////////////////////////////////////////////////////////////////////
  42. // map of HINTERNETs to CInternetSessions* for callbacks
  43.  
  44. // forward declared because we need a #pragma -- see end of this file
  45.  
  46. class CSessionMapPtrToPtr : public CMapPtrToPtr
  47. {
  48. private:
  49.     CCriticalSection m_sect;
  50.  
  51. public:
  52.     CSessionMapPtrToPtr() { }
  53.     ~CSessionMapPtrToPtr() { }
  54.  
  55.     void SetAt(HINTERNET hInternet, CInternetSession* pSess)
  56.     {
  57.         m_sect.Lock();
  58.         CMapPtrToPtr::SetAt(hInternet, pSess);
  59.         m_sect.Unlock();
  60.     }
  61.  
  62.     void RemoveKey(HINTERNET hInternet)
  63.     {
  64.         m_sect.Lock();
  65.         CMapPtrToPtr::RemoveKey(hInternet);
  66.         m_sect.Unlock();
  67.     }
  68.  
  69.     BOOL Lookup(HINTERNET hInternet, CInternetSession*& refpSession)
  70.     {
  71.         BOOL bRet;
  72.         m_sect.Lock();
  73.         bRet = CMapPtrToPtr::Lookup(hInternet, (void*&) refpSession);
  74.         m_sect.Unlock();
  75.         return bRet;
  76.     }
  77. };
  78.  
  79. extern CSessionMapPtrToPtr _afxSessionMap;
  80.  
  81.  
  82. /////////////////////////////////////////////////////////////////////////////
  83. // Global Functions
  84.  
  85. static BOOL AFXAPI _AfxParseURLWorker(LPCTSTR pstrURL,
  86.     LPURL_COMPONENTS lpComponents, DWORD& dwServiceType,
  87.     INTERNET_PORT& nPort, DWORD dwFlags)
  88. {
  89.     // this function will return bogus stuff if lpComponents
  90.     // isn't set up to copy the components
  91.  
  92.     ASSERT(lpComponents != NULL && pstrURL != NULL);
  93.     if (lpComponents == NULL || pstrURL == NULL)
  94.         return FALSE;
  95.     ASSERT(lpComponents->dwHostNameLength == 0 ||
  96.             lpComponents->lpszHostName != NULL);
  97.     ASSERT(lpComponents->dwUrlPathLength == 0 ||
  98.             lpComponents->lpszUrlPath != NULL);
  99.     ASSERT(lpComponents->dwUserNameLength == 0 ||
  100.             lpComponents->lpszUserName != NULL);
  101.     ASSERT(lpComponents->dwPasswordLength == 0 ||
  102.             lpComponents->lpszPassword != NULL);
  103.  
  104.     LPTSTR pstrCanonicalizedURL;
  105.     TCHAR szCanonicalizedURL[INTERNET_MAX_URL_LENGTH];
  106.     DWORD dwNeededLength = INTERNET_MAX_URL_LENGTH;
  107.     BOOL bRetVal;
  108.     BOOL bMustFree = FALSE;
  109.     DWORD dwCanonicalizeFlags = dwFlags &
  110.         (ICU_NO_ENCODE | ICU_DECODE | ICU_NO_META |
  111.         ICU_ENCODE_SPACES_ONLY | ICU_BROWSER_MODE);
  112.     DWORD dwCrackFlags = dwFlags & (ICU_ESCAPE | ICU_USERNAME);
  113.  
  114.     bRetVal = InternetCanonicalizeUrl(pstrURL, szCanonicalizedURL,
  115.         &dwNeededLength, dwCanonicalizeFlags);
  116.  
  117.     if (!bRetVal)
  118.     {
  119.         if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  120.             return FALSE;
  121.  
  122.         pstrCanonicalizedURL = new TCHAR[dwNeededLength];
  123.         bMustFree = TRUE;
  124.         bRetVal = InternetCanonicalizeUrl(pstrURL, pstrCanonicalizedURL,
  125.             &dwNeededLength, dwCanonicalizeFlags);
  126.         if (bRetVal == FALSE)
  127.         {
  128.             delete [] pstrCanonicalizedURL;
  129.             return FALSE;
  130.         }
  131.     }
  132.     else
  133.         pstrCanonicalizedURL = szCanonicalizedURL;
  134.  
  135.     // now that it's safely canonicalized, crack it
  136.  
  137.     bRetVal = InternetCrackUrl(pstrCanonicalizedURL, 0,
  138.                         dwCrackFlags, lpComponents);
  139.     if (bMustFree)
  140.         delete [] pstrCanonicalizedURL;
  141.  
  142.     // convert to MFC-style service ID
  143.  
  144.     if (!bRetVal)
  145.         dwServiceType = AFX_INET_SERVICE_UNK;
  146.     else
  147.     {
  148.         nPort = lpComponents->nPort;
  149.         switch (lpComponents->nScheme)
  150.         {
  151.         case INTERNET_SCHEME_FTP:
  152.             dwServiceType = AFX_INET_SERVICE_FTP;
  153.             break;
  154.  
  155.         case INTERNET_SCHEME_GOPHER:
  156.             dwServiceType = AFX_INET_SERVICE_GOPHER;
  157.             break;
  158.  
  159.         case INTERNET_SCHEME_HTTP:
  160.             dwServiceType = AFX_INET_SERVICE_HTTP;
  161.             break;
  162.  
  163.         case INTERNET_SCHEME_HTTPS:
  164.             dwServiceType = AFX_INET_SERVICE_HTTPS;
  165.             break;
  166.  
  167.         case INTERNET_SCHEME_FILE:
  168.             dwServiceType = AFX_INET_SERVICE_FILE;
  169.             break;
  170.  
  171.         case INTERNET_SCHEME_NEWS:
  172.             dwServiceType = AFX_INET_SERVICE_NNTP;
  173.             break;
  174.  
  175.         case INTERNET_SCHEME_MAILTO:
  176.             dwServiceType = AFX_INET_SERVICE_MAILTO;
  177.             break;
  178.  
  179.         default:
  180.             dwServiceType = AFX_INET_SERVICE_UNK;
  181.         }
  182.     }
  183.  
  184.     return bRetVal;
  185. }
  186.  
  187. BOOL AFXAPI AfxParseURLEx(LPCTSTR pstrURL, DWORD& dwServiceType,
  188.     CString& strServer, CString& strObject, INTERNET_PORT& nPort,
  189.     CString& strUsername, CString& strPassword, DWORD dwFlags/* = 0*/)
  190. {
  191.     dwServiceType = AFX_INET_SERVICE_UNK;
  192.  
  193.     ASSERT(pstrURL != NULL);
  194.     if (pstrURL == NULL)
  195.         return FALSE;
  196.  
  197.     URL_COMPONENTS urlComponents;
  198.     memset(&urlComponents, 0, sizeof(URL_COMPONENTS));
  199.     urlComponents.dwStructSize = sizeof(URL_COMPONENTS);
  200.  
  201.     urlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
  202.     urlComponents.lpszHostName = strServer.GetBuffer(INTERNET_MAX_HOST_NAME_LENGTH+1);
  203.     urlComponents.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
  204.     urlComponents.lpszUrlPath = strObject.GetBuffer(INTERNET_MAX_PATH_LENGTH+1);
  205.     urlComponents.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH;
  206.     urlComponents.lpszUserName = strUsername.GetBuffer(INTERNET_MAX_USER_NAME_LENGTH+1);
  207.     urlComponents.dwPasswordLength = INTERNET_MAX_PASSWORD_LENGTH;
  208.     urlComponents.lpszPassword = strPassword.GetBuffer(INTERNET_MAX_PASSWORD_LENGTH+1);
  209.  
  210.     BOOL bRetVal = _AfxParseURLWorker(pstrURL, &urlComponents,
  211.                     dwServiceType, nPort, dwFlags);
  212.  
  213.     strServer.ReleaseBuffer();
  214.     strObject.ReleaseBuffer();
  215.     strUsername.ReleaseBuffer();
  216.     strPassword.ReleaseBuffer();
  217.     return bRetVal;
  218. }
  219.  
  220. BOOL AFXAPI AfxParseURL(LPCTSTR pstrURL, DWORD& dwServiceType,
  221.     CString& strServer, CString& strObject, INTERNET_PORT& nPort)
  222. {
  223.     dwServiceType = AFX_INET_SERVICE_UNK;
  224.  
  225.     ASSERT(pstrURL != NULL);
  226.     if (pstrURL == NULL)
  227.         return FALSE;
  228.  
  229.     URL_COMPONENTS urlComponents;
  230.     memset(&urlComponents, 0, sizeof(URL_COMPONENTS));
  231.     urlComponents.dwStructSize = sizeof(URL_COMPONENTS);
  232.  
  233.     urlComponents.dwHostNameLength = INTERNET_MAX_URL_LENGTH;
  234.     urlComponents.lpszHostName = strServer.GetBuffer(INTERNET_MAX_URL_LENGTH+1);
  235.     urlComponents.dwUrlPathLength = INTERNET_MAX_URL_LENGTH;
  236.     urlComponents.lpszUrlPath = strObject.GetBuffer(INTERNET_MAX_URL_LENGTH+1);
  237.  
  238.     BOOL bRetVal = _AfxParseURLWorker(pstrURL, &urlComponents,
  239.                     dwServiceType, nPort, ICU_BROWSER_MODE);
  240.  
  241.     strServer.ReleaseBuffer();
  242.     strObject.ReleaseBuffer();
  243.     return bRetVal;
  244. }
  245.  
  246.  
  247. DWORD AFXAPI AfxGetInternetHandleType(HINTERNET hQuery)
  248. {
  249.     DWORD dwServiceType;
  250.     DWORD dwTypeLen = sizeof(dwServiceType);
  251.     if (hQuery == NULL ||
  252.         !InternetQueryOption(hQuery, INTERNET_OPTION_HANDLE_TYPE,
  253.             &dwServiceType, &dwTypeLen))
  254.         return AFX_INET_SERVICE_UNK;
  255.     else
  256.         return dwServiceType;
  257. }
  258.  
  259. static BOOL _AfxQueryCStringInternetOption(HINTERNET hHandle, DWORD dwOption, CString& refString)
  260. {
  261.     DWORD dwLength = 0;
  262.     LPTSTR pstrBuffer;
  263.  
  264.     if (hHandle == NULL)
  265.         return FALSE;
  266.  
  267.     if (!InternetQueryOption(hHandle, dwOption, NULL, &dwLength) &&
  268.         GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  269.     {
  270.         refString.Empty();
  271.         return FALSE;
  272.     }
  273.  
  274.     pstrBuffer = refString.GetBuffer(dwLength);
  275.     BOOL bRet = InternetQueryOption(hHandle, dwOption, pstrBuffer, &dwLength);
  276.     refString.ReleaseBuffer();
  277.     return bRet;
  278. }
  279.  
  280. #ifdef _DEBUG
  281. void AFXAPI AfxInternetStatusCallbackDebug(HINTERNET hInternet,
  282.     DWORD dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation,
  283.     DWORD dwStatusInformationLength)
  284. {
  285.     UNUSED_ALWAYS(hInternet);
  286.     TRACE1("Internet ctxt=%d: ", dwContext);
  287.  
  288.     switch (dwInternetStatus)
  289.     {
  290.     case INTERNET_STATUS_RESOLVING_NAME:
  291.         TRACE1("resolving name for %s\n", lpvStatusInformation);
  292.         break;
  293.  
  294.     case INTERNET_STATUS_NAME_RESOLVED:
  295.         TRACE1("resolved name for %s!\n", lpvStatusInformation);
  296.         break;
  297.  
  298.     case INTERNET_STATUS_HANDLE_CREATED:
  299.         TRACE1("handle %8.8X created\n", hInternet);
  300.         break;
  301.  
  302.     case INTERNET_STATUS_CONNECTING_TO_SERVER:
  303.         {
  304.         sockaddr* pSockAddr = (sockaddr*) lpvStatusInformation;
  305.         TRACE1("connecting to socket address \"%s\"\n", pSockAddr->sa_data);
  306.         }
  307.         break;
  308.  
  309.     case INTERNET_STATUS_REQUEST_SENT:
  310.         TRACE0("request sent!\n");
  311.         break;
  312.  
  313.     case INTERNET_STATUS_SENDING_REQUEST:
  314.         TRACE0("sending request...\n");
  315.         break;
  316.  
  317.     case INTERNET_STATUS_CONNECTED_TO_SERVER:
  318.         TRACE0("connected to socket address!\n");
  319.         break;
  320.  
  321.     case INTERNET_STATUS_RECEIVING_RESPONSE:
  322.         TRACE0("receiving response...\n");
  323.         break;
  324.  
  325.     case INTERNET_STATUS_RESPONSE_RECEIVED:
  326.         TRACE0("response received!\n");
  327.         break;
  328.  
  329.     case INTERNET_STATUS_CLOSING_CONNECTION:
  330.         TRACE1("closing connection %8.8X\n", hInternet);
  331.         break;
  332.  
  333.     case INTERNET_STATUS_CONNECTION_CLOSED:
  334.         TRACE1("connection %8.8X closed!\n", hInternet);
  335.         break;
  336.  
  337.     case INTERNET_STATUS_HANDLE_CLOSING:
  338.         TRACE1("handle %8.8X closed!\n", hInternet);
  339.         break;
  340.  
  341.     case INTERNET_STATUS_REQUEST_COMPLETE:
  342.         if (dwStatusInformationLength == sizeof(INTERNET_ASYNC_RESULT))
  343.         {
  344.             INTERNET_ASYNC_RESULT* pResult = (INTERNET_ASYNC_RESULT*) lpvStatusInformation;
  345.             TRACE2("request complete, dwResult = %8.8X, dwError = %8.8X\n",
  346.                 pResult->dwResult, pResult->dwError);
  347.         }
  348.         else
  349.             TRACE0("request complete.\n");
  350.         break;
  351.  
  352.     case INTERNET_STATUS_CTL_RESPONSE_RECEIVED:
  353.     case INTERNET_STATUS_REDIRECT:
  354.     default:
  355.         TRACE1("Unknown status: %d\n", dwInternetStatus);
  356.         break;
  357.     }
  358.  
  359.     return;
  360. }
  361. #endif // _DEBUG
  362.  
  363. void AFXAPI AfxInternetStatusCallback(HINTERNET hInternet, DWORD dwContext,
  364.     DWORD dwInternetStatus, LPVOID lpvStatusInformation,
  365.     DWORD dwStatusInformationLength)
  366. {
  367.     CInternetSession* pSession;
  368.  
  369. #ifdef _DEBUG
  370.     if (afxTraceFlags & traceInternet)
  371.         AfxInternetStatusCallbackDebug(hInternet, dwContext,
  372.             dwInternetStatus, lpvStatusInformation, dwStatusInformationLength);
  373. #endif
  374.  
  375.     if (_afxSessionMap.Lookup(hInternet, pSession))
  376.     {
  377.         pSession->OnStatusCallback(dwContext, dwInternetStatus,
  378.             lpvStatusInformation, dwStatusInformationLength);
  379.     }
  380.  
  381.     // note that an entry we can't match is simply ignored as
  382.     // WININET can send notifications for handles that we can't
  383.     // see -- such as when using InternetOpenURL()
  384. }
  385.  
  386.  
  387. /////////////////////////////////////////////////////////////////////////////
  388. // CInternetSession
  389.  
  390. CInternetSession::~CInternetSession()
  391. {
  392.     Close();
  393. }
  394.  
  395. CInternetSession::CInternetSession(LPCTSTR pstrAgent /* = NULL */,
  396.     DWORD dwContext /* = 1 */,
  397.     DWORD dwAccessType /* = PRE_CONFIG_INTERNET_ACCESS */,
  398.     LPCTSTR pstrProxyName /* = NULL */,
  399.     LPCTSTR pstrProxyBypass /* = NULL */,
  400.     DWORD dwFlags /* = 0 */)
  401. {
  402.     m_bCallbackEnabled = FALSE;
  403.     m_pOldCallback = NULL;
  404.  
  405.     m_dwContext = dwContext;
  406.     if (pstrAgent == NULL)
  407.         pstrAgent = AfxGetAppName();
  408.     m_hSession = InternetOpen(pstrAgent, dwAccessType,
  409.         pstrProxyName, pstrProxyBypass, dwFlags);
  410.  
  411.     if (m_hSession == NULL)
  412.         AfxThrowInternetException(m_dwContext);
  413.     else
  414.         _afxSessionMap.SetAt(m_hSession, this);
  415. }
  416.  
  417. void CInternetSession::Close()
  418. {
  419.     if (m_bCallbackEnabled)
  420.         EnableStatusCallback(FALSE);
  421.  
  422.     if (m_hSession != NULL)
  423.     {
  424.         InternetCloseHandle(m_hSession);
  425.         _afxSessionMap.RemoveKey(m_hSession);
  426.         m_hSession = NULL;
  427.     }
  428. }
  429.  
  430. CGopherConnection* CInternetSession::GetGopherConnection(LPCTSTR pstrServer,
  431.     LPCTSTR pstrUserName /* = NULL */, LPCTSTR pstrPassword /* = NULL */,
  432.     INTERNET_PORT nPort /* = INTERNET_INVALID_PORT_NUMBER */)
  433. {
  434.     ASSERT(pstrServer != NULL);
  435.  
  436.     CGopherConnection* pReturn = new CGopherConnection(this,
  437.         pstrServer, pstrUserName, pstrPassword, m_dwContext, nPort);
  438.     return pReturn;
  439. }
  440.  
  441. CFtpConnection* CInternetSession::GetFtpConnection(LPCTSTR pstrServer,
  442.     LPCTSTR pstrUserName /* = NULL */, LPCTSTR pstrPassword /* = NULL */,
  443.     INTERNET_PORT nPort /* = INTERNET_INVALID_PORT_NUMBER */,
  444.     BOOL bPassive /* = FALSE */)
  445. {
  446.     ASSERT(pstrServer != NULL);
  447.  
  448.     CFtpConnection* pReturn = new CFtpConnection(this,
  449.         pstrServer, pstrUserName, pstrPassword, m_dwContext,
  450.         nPort, bPassive);
  451.     return pReturn;
  452. }
  453.  
  454. CHttpConnection* CInternetSession::GetHttpConnection(LPCTSTR pstrServer,
  455.     INTERNET_PORT nPort /* = INTERNET_INVALID_PORT_NUMBER */,
  456.     LPCTSTR pstrUserName /* = NULL */, LPCTSTR pstrPassword /* = NULL */)
  457. {
  458.     ASSERT(pstrServer != NULL);
  459.  
  460.     CHttpConnection* pReturn = new CHttpConnection(this,
  461.         pstrServer, nPort, pstrUserName, pstrPassword, m_dwContext);
  462.     return pReturn;
  463. }
  464.  
  465. CHttpConnection* CInternetSession::GetHttpConnection(LPCTSTR pstrServer,
  466.     DWORD dwFlags, INTERNET_PORT nPort /* = INTERNET_INVALID_PORT_NUMBER */,
  467.     LPCTSTR pstrUserName /* = NULL */, LPCTSTR pstrPassword /* = NULL */)
  468. {
  469.     ASSERT(pstrServer != NULL);
  470.  
  471.     CHttpConnection* pReturn = new CHttpConnection(this, pstrServer,
  472.             dwFlags, nPort, pstrUserName, pstrPassword, m_dwContext);
  473.     return pReturn;
  474. }
  475.  
  476. CStdioFile* CInternetSession::OpenURL(LPCTSTR pstrURL,
  477.     DWORD dwContext /* = 0 */, DWORD dwFlags /* = INTERNET_FLAG_TRANSFER_BINARY */,
  478.     LPCTSTR pstrHeaders /* = NULL */, DWORD dwHeadersLength /* = 0 */)
  479. {
  480.     ASSERT(pstrURL != NULL);
  481.     ASSERT(dwHeadersLength == 0 || pstrHeaders != NULL);
  482.  
  483.     // must have TRANSFER_BINARY or TRANSFER_ASCII but not both
  484. #define _AFX_TRANSFER_MASK (INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_TRANSFER_ASCII)
  485.     ASSERT((dwFlags & _AFX_TRANSFER_MASK) != 0);
  486.     ASSERT((dwFlags & _AFX_TRANSFER_MASK) != _AFX_TRANSFER_MASK);
  487.  
  488.     if (dwContext == 1)
  489.         dwContext = m_dwContext;
  490.  
  491.     DWORD dwServiceType;
  492.     CString strServer;
  493.     CString strObject;
  494.     INTERNET_PORT nPort;
  495.     CStdioFile* pReturn;
  496.  
  497.     BOOL bParsed = AfxParseURL(pstrURL, dwServiceType, strServer, strObject, nPort);
  498.  
  499.     // if it turns out to be a file...
  500.     if (bParsed && dwServiceType == AFX_INET_SERVICE_FILE)
  501.     {
  502.         int nMode = CFile::modeRead | CFile::shareCompat;
  503.         if (dwFlags & INTERNET_FLAG_TRANSFER_BINARY)
  504.             nMode |= CFile::typeBinary;
  505.         else
  506.             nMode |= CFile::typeText;
  507.  
  508.         pReturn = new CStdioFile(strObject, nMode);
  509.     }
  510.     else
  511.     {
  512.         HINTERNET hOpener;
  513.  
  514.         hOpener = InternetOpenUrl(m_hSession, pstrURL, pstrHeaders,
  515.             dwHeadersLength, dwFlags, dwContext);
  516.  
  517.         if (hOpener == NULL)
  518.             AfxThrowInternetException(m_dwContext);
  519.  
  520.         if (!bParsed)
  521.             dwServiceType = AfxGetInternetHandleType(hOpener);
  522.  
  523.         switch (dwServiceType)
  524.         {
  525.             case INTERNET_HANDLE_TYPE_GOPHER_FILE:
  526.             case AFX_INET_SERVICE_GOPHER:
  527.             //WINBUG: WININET supplies no way to
  528.             // convert from a URL to a Gopher locator
  529.                 pReturn = new CGopherFile(hOpener, m_hSession, _T(""),
  530.                     0, dwContext);
  531.                 _afxSessionMap.SetAt(hOpener, this);
  532.                 break;
  533.  
  534.             case INTERNET_HANDLE_TYPE_FTP_FILE:
  535.             case AFX_INET_SERVICE_FTP:
  536.                 pReturn = new CInternetFile(hOpener, m_hSession, strObject,
  537.                     strServer, dwContext, TRUE);
  538.                 _afxSessionMap.SetAt(hOpener, this);
  539.                 break;
  540.  
  541.             case INTERNET_HANDLE_TYPE_HTTP_REQUEST:
  542.             case AFX_INET_SERVICE_HTTP:
  543.             case AFX_INET_SERVICE_HTTPS:
  544.                 pReturn = new CHttpFile(hOpener, m_hSession, strObject, strServer,
  545.                     CHttpConnection::szHtmlVerbs[CHttpConnection::HTTP_VERB_GET],
  546.                     dwContext);
  547.                 _afxSessionMap.SetAt(hOpener, this);
  548.                 break;
  549.  
  550.             default:
  551.                 TRACE1("Error: Unidentified service type: %8.8X\n", dwServiceType);
  552.                 pReturn = NULL;
  553.         }
  554.     }
  555.  
  556.     return pReturn;
  557. }
  558.  
  559. BOOL CInternetSession::SetOption(DWORD dwOption, LPVOID lpBuffer,
  560.     DWORD dwBufferLength, DWORD dwFlags /* = 0 */)
  561. {
  562.     ASSERT(dwOption >= INTERNET_FIRST_OPTION &&
  563.         dwOption <= INTERNET_LAST_OPTION);
  564.     ASSERT(lpBuffer != NULL);
  565.     ASSERT(dwBufferLength != 0);
  566.  
  567.     // bogus flag?
  568.     ASSERT(dwFlags == 0 || ((dwFlags & ISO_VALID_FLAGS) == dwFlags));
  569.  
  570.     return InternetSetOptionEx(m_hSession, dwOption,
  571.         lpBuffer, dwBufferLength, dwFlags);
  572. }
  573.  
  574. BOOL CInternetSession::QueryOption(DWORD dwOption, LPVOID lpBuffer,
  575.     LPDWORD lpdwBufferLength) const
  576. {
  577.     ASSERT(dwOption >= INTERNET_FIRST_OPTION &&
  578.         dwOption <= INTERNET_LAST_OPTION);
  579.     ASSERT(lpBuffer != NULL);
  580.     ASSERT(lpdwBufferLength != NULL);
  581.     ASSERT(*lpdwBufferLength != 0);
  582.  
  583.     return InternetQueryOption(m_hSession, dwOption,
  584.         lpBuffer, lpdwBufferLength);
  585. }
  586.  
  587. BOOL CInternetSession::QueryOption(DWORD dwOption, DWORD& dwValue) const
  588. {
  589.     DWORD dwLen = sizeof(DWORD);
  590.     return InternetQueryOption(m_hSession, dwOption,
  591.         &dwValue, &dwLen);
  592. }
  593.  
  594. BOOL CInternetSession::QueryOption(DWORD dwOption, CString& refString) const
  595. {
  596.     ASSERT(dwOption >= INTERNET_FIRST_OPTION &&
  597.         dwOption <= INTERNET_LAST_OPTION);
  598.  
  599.     return _AfxQueryCStringInternetOption(m_hSession, dwOption, refString);
  600. }
  601.  
  602. void CInternetSession::OnStatusCallback(DWORD dwContext,
  603.     DWORD dwInternetStatus, LPVOID lpvStatusInformation,
  604.     DWORD dwStatusInformationLength)
  605. {
  606.     ASSERT(m_bCallbackEnabled != NULL);
  607.  
  608.     if (m_pOldCallback != NULL)
  609.     {
  610.         (*m_pOldCallback)(m_hSession, dwContext, dwInternetStatus,
  611.             lpvStatusInformation, dwStatusInformationLength);
  612.     }
  613. }
  614.  
  615. BOOL CInternetSession::EnableStatusCallback(BOOL bEnable /* = TRUE */)
  616. {
  617.     ASSERT(bEnable == FALSE || m_hSession != NULL);
  618.     if (m_hSession == NULL)
  619.         return FALSE;
  620.  
  621.     BOOL bResult = TRUE;
  622.  
  623.     if (bEnable)
  624.     {
  625.         ASSERT(!m_bCallbackEnabled);
  626.         if (!m_bCallbackEnabled)
  627.         {
  628.             INTERNET_STATUS_CALLBACK pRet =
  629.                 InternetSetStatusCallback(m_hSession, AfxInternetStatusCallback);
  630.  
  631.             if (pRet != INTERNET_INVALID_STATUS_CALLBACK)
  632.             {
  633.                 m_pOldCallback = pRet;
  634.                 m_bCallbackEnabled = TRUE;
  635.             }
  636.             else
  637.                 AfxThrowInternetException(m_dwContext);
  638.         }
  639.     }
  640.     else
  641.     {
  642.         ASSERT(m_bCallbackEnabled);
  643.  
  644.         if (m_bCallbackEnabled)
  645.         {
  646.             InternetSetStatusCallback(m_hSession, NULL);
  647.             m_bCallbackEnabled = FALSE;
  648.         }
  649.     }
  650.  
  651.     return bResult;
  652. }
  653.  
  654. #ifdef _DEBUG
  655. void CInternetSession::Dump(CDumpContext& dc) const
  656. {
  657.     CObject::Dump(dc);
  658.     dc << "m_hSession = " << m_hSession;
  659.     dc << "\nm_dwContext = " << m_dwContext;
  660. }
  661. #endif
  662.  
  663.  
  664. /////////////////////////////////////////////////////////////////////////////
  665. // Internet Files
  666.  
  667. CInternetFile::CInternetFile(HINTERNET hFile, HINTERNET /* hSession */,
  668.     LPCTSTR pstrFileName, LPCTSTR pstrServer, DWORD dwContext, BOOL bReadMode)
  669.     : m_dwContext(dwContext)
  670. {
  671.     // caller must set _afxSessionMap()!
  672.  
  673.     ASSERT(pstrServer != NULL);
  674.     ASSERT(pstrFileName != NULL);
  675.     ASSERT(hFile != NULL);
  676.  
  677.     m_strFileName = pstrFileName;
  678.     m_strServerName = pstrServer;
  679.  
  680.     m_hFile = hFile;
  681.     m_bReadMode = bReadMode;
  682.  
  683.     m_pbReadBuffer = NULL;
  684.     m_pbWriteBuffer = NULL;
  685.  
  686.     m_nReadBufferSize = 0;
  687.     m_nReadBufferPos = 0;
  688.     m_nWriteBufferSize = 0;
  689.     m_nWriteBufferPos = 0;
  690.     m_nReadBufferBytes = 0;
  691. }
  692.  
  693. CInternetFile::CInternetFile(HINTERNET hFile,
  694.     LPCTSTR pstrFileName, CInternetConnection* pConnection, BOOL bReadMode)
  695. {
  696.     ASSERT(pstrFileName != NULL);
  697.     ASSERT(pConnection != NULL);
  698.     ASSERT_VALID(pConnection);
  699.     ASSERT(hFile != NULL);
  700.  
  701.     _afxSessionMap.SetAt(hFile, pConnection->GetSession());
  702.  
  703.     m_strFileName = pstrFileName;
  704.  
  705.     m_dwContext = pConnection->GetContext();
  706.     m_strServerName = pConnection->GetServerName();
  707.     m_hFile = hFile;
  708.     m_bReadMode = bReadMode;
  709.  
  710.     m_pbReadBuffer = NULL;
  711.     m_pbWriteBuffer = NULL;
  712.  
  713.     m_nReadBufferSize = 0;
  714.     m_nReadBufferPos = 0;
  715.     m_nWriteBufferSize = 0;
  716.     m_nWriteBufferPos = 0;
  717.     m_nReadBufferBytes = 0;
  718. }
  719.  
  720. BOOL CInternetFile::QueryOption(DWORD dwOption, LPVOID lpBuffer,
  721.     LPDWORD lpdwBufferLength) const
  722. {
  723.     ASSERT(dwOption >= INTERNET_FIRST_OPTION &&
  724.         dwOption <= INTERNET_LAST_OPTION);
  725.     ASSERT(lpBuffer != NULL);
  726.     ASSERT(lpdwBufferLength != NULL);
  727.     ASSERT(*lpdwBufferLength != 0);
  728.     ASSERT(m_hFile != NULL);
  729.  
  730.     return InternetQueryOption(m_hFile, dwOption,
  731.         lpBuffer, lpdwBufferLength);
  732. }
  733.  
  734. BOOL CInternetFile::QueryOption(DWORD dwOption, DWORD& dwValue) const
  735. {
  736.     ASSERT(m_hFile != NULL);
  737.  
  738.     DWORD dwLen = sizeof(DWORD);
  739.     return InternetQueryOption(m_hFile, dwOption,
  740.         &dwValue, &dwLen);
  741. }
  742.  
  743. BOOL CInternetFile::QueryOption(DWORD dwOption, CString& refString) const
  744. {
  745.     ASSERT(dwOption >= INTERNET_FIRST_OPTION &&
  746.         dwOption <= INTERNET_LAST_OPTION);
  747.     ASSERT(m_hFile != NULL);
  748.  
  749.     return _AfxQueryCStringInternetOption(m_hFile, dwOption, refString);
  750. }
  751.  
  752. BOOL CInternetFile::SetOption(DWORD dwOption, LPVOID lpBuffer,
  753.     DWORD dwBufferLength, DWORD dwFlags /* = 0 */)
  754. {
  755.     ASSERT(dwOption >= INTERNET_FIRST_OPTION &&
  756.         dwOption <= INTERNET_LAST_OPTION);
  757.     ASSERT(lpBuffer != NULL);
  758.     ASSERT(dwBufferLength != 0);
  759.  
  760.     // bogus flag?
  761.     ASSERT(dwFlags == 0 || ((dwFlags & ISO_VALID_FLAGS) == dwFlags));
  762.  
  763.     return InternetSetOptionEx(m_hFile, dwOption,
  764.         lpBuffer, dwBufferLength, dwFlags);
  765. }
  766.  
  767. BOOL CInternetFile::SetReadBufferSize(UINT nReadSize)
  768. {
  769.     ASSERT_VALID(this);
  770.     BOOL bRet = TRUE;
  771.  
  772.     if (nReadSize != -1 && nReadSize != m_nReadBufferSize)
  773.     {
  774.         if (m_nReadBufferPos > nReadSize)
  775.             bRet = FALSE;
  776.         else
  777.         {
  778.             if (nReadSize == 0)
  779.             {
  780.                 delete [] m_pbReadBuffer;
  781.                 m_pbReadBuffer = NULL;
  782.             }
  783.             else if (m_pbReadBuffer == NULL)
  784.             {
  785.                 m_pbReadBuffer = new BYTE[nReadSize];
  786.                 m_nReadBufferPos = nReadSize;
  787.             }
  788.             else
  789.             {
  790.                 DWORD dwMoved = m_nReadBufferSize - m_nReadBufferPos;
  791.                 LPBYTE pbTemp = m_pbReadBuffer;
  792.                 m_pbReadBuffer = new BYTE[nReadSize];
  793.  
  794.                 if (dwMoved > 0)
  795.                 {
  796.                     memcpy(m_pbReadBuffer, pbTemp + m_nReadBufferPos, dwMoved);
  797.                     m_nReadBufferPos = 0;
  798.                     m_nReadBufferBytes = dwMoved;
  799.                 }
  800.                 else
  801.                 {
  802.                     m_nReadBufferBytes = 0;
  803.                     m_nReadBufferPos = nReadSize;
  804.                 }
  805.                 delete [] pbTemp;
  806.             }
  807.  
  808.             m_nReadBufferSize = nReadSize;
  809.         }
  810.     }
  811.  
  812.     return bRet;
  813. }
  814.  
  815. BOOL CInternetFile::SetWriteBufferSize(UINT nWriteSize)
  816. {
  817.     ASSERT_VALID(this);
  818.     BOOL bRet = TRUE;
  819.  
  820.     if (nWriteSize != m_nWriteBufferSize)
  821.     {
  822.         if (m_nWriteBufferPos > nWriteSize)
  823.             Flush();
  824.  
  825.         if (nWriteSize == 0)
  826.         {
  827.             delete [] m_pbWriteBuffer;
  828.             m_pbWriteBuffer = NULL;
  829.         }
  830.         else if (m_pbWriteBuffer == NULL)
  831.         {
  832.             m_pbWriteBuffer = new BYTE[nWriteSize];
  833.             m_nWriteBufferPos = 0;
  834.         }
  835.         else
  836.         {
  837.             LPBYTE pbTemp = m_pbWriteBuffer;
  838.             m_pbWriteBuffer = new BYTE[nWriteSize];
  839.  
  840.             memcpy(m_pbWriteBuffer, pbTemp, m_nWriteBufferPos);
  841.             delete [] pbTemp;
  842.         }
  843.  
  844.         m_nWriteBufferSize = nWriteSize;
  845.     }
  846.  
  847.     return bRet;
  848. }
  849.  
  850. LONG CInternetFile::Seek(LONG lOffset, UINT nFrom)
  851. {
  852.     ASSERT_VALID(this);
  853.     ASSERT(m_hFile != NULL);
  854.     ASSERT(m_bReadMode == TRUE);
  855.     ASSERT(m_pbReadBuffer == NULL);
  856.  
  857.     // can't do this on a file for writing
  858.     // cna't do this on a file that's got a buffer
  859.     if (!m_bReadMode || m_pbReadBuffer != NULL)
  860.         AfxThrowInternetException(m_dwContext, ERROR_INVALID_HANDLE);
  861.  
  862.     switch (nFrom)
  863.     {
  864.         case begin:
  865.             nFrom = FILE_BEGIN;
  866.             break;
  867.  
  868.         case current:
  869.             nFrom = FILE_CURRENT;
  870.             break;
  871.  
  872.         case end:
  873.             nFrom = FILE_END;
  874.             break;
  875.  
  876.         default:
  877.             ASSERT(FALSE);  // got a bogus nFrom value
  878.             AfxThrowInternetException(m_dwContext, ERROR_INVALID_PARAMETER);
  879.             break;
  880.     }
  881.  
  882.     LONG lRet;
  883.     lRet = InternetSetFilePointer(m_hFile, lOffset, NULL, nFrom, m_dwContext);
  884.     if (lRet == -1)
  885.         AfxThrowInternetException(m_dwContext);
  886.  
  887.     return lRet;
  888. }
  889.  
  890. CInternetFile::~CInternetFile()
  891. {
  892.     if (m_hFile != NULL)
  893.     {
  894. #ifdef _DEBUG
  895.         USES_CONVERSION;
  896.         LPCTSTR pszName = A2CT(GetRuntimeClass()->m_lpszClassName);
  897.         TRACE2("Warning: destroying an open %s with handle %8.8X\n",
  898.             pszName, m_hFile);
  899. #endif
  900.         Close();
  901.     }
  902.  
  903.     if (m_pbReadBuffer != NULL)
  904.         delete m_pbReadBuffer;
  905.  
  906.     if (m_pbWriteBuffer != NULL)
  907.         delete m_pbWriteBuffer;
  908. }
  909.  
  910. void CInternetFile::Abort()
  911. {
  912.     ASSERT_VALID(this);
  913.     if (m_hFile != NULL)
  914.         Close();
  915.     m_strFileName.Empty();
  916. }
  917.  
  918. void CInternetFile::Flush()
  919. {
  920.     if (m_pbWriteBuffer != NULL && m_nWriteBufferPos > 0)
  921.     {
  922.         DWORD dwBytes;
  923.  
  924.         if (!InternetWriteFile(m_hFile, m_pbWriteBuffer,
  925.                 m_nWriteBufferPos, &dwBytes))
  926.             AfxThrowInternetException(m_dwContext);
  927.  
  928.         if (dwBytes != m_nWriteBufferPos)
  929.             AfxThrowInternetException(m_dwContext);
  930.  
  931.         m_nWriteBufferPos = 0;
  932.     }
  933. }
  934.  
  935. void CInternetFile::Close()
  936. {
  937.     if (m_hFile != NULL)
  938.     {
  939.         Flush();
  940.         InternetCloseHandle(m_hFile);
  941.         _afxSessionMap.RemoveKey(m_hFile);
  942.         m_hFile = NULL;
  943.  
  944.         if (m_pbWriteBuffer != NULL)
  945.         {
  946.             delete [] m_pbWriteBuffer;
  947.             m_pbWriteBuffer = NULL;
  948.         }
  949.  
  950.         if (m_pbReadBuffer != NULL)
  951.         {
  952.             delete [] m_pbReadBuffer;
  953.             m_pbReadBuffer = NULL;
  954.         }
  955.     }
  956. }
  957.  
  958. UINT CInternetFile::Read(LPVOID lpBuf, UINT nCount)
  959. {
  960.     ASSERT_VALID(this);
  961.     ASSERT(m_hFile != NULL);
  962.     ASSERT(m_bReadMode);
  963.  
  964.     DWORD dwBytes;
  965.  
  966.     if (!m_bReadMode || m_hFile == NULL)
  967.         AfxThrowInternetException(m_dwContext, ERROR_INVALID_HANDLE);
  968.  
  969.     if (m_pbReadBuffer == NULL)
  970.     {
  971.         if (!InternetReadFile(m_hFile, (LPVOID) lpBuf, nCount, &dwBytes))
  972.                 AfxThrowInternetException(m_dwContext);
  973.         return dwBytes;
  974.     }
  975.  
  976.     LPBYTE lpbBuf = (LPBYTE) lpBuf;
  977.  
  978.     // if the requested size is bigger than our buffer,
  979.     // then handle it directly
  980.  
  981.     if (nCount >= m_nReadBufferSize)
  982.     {
  983.         DWORD dwMoved = max(0, (long)m_nReadBufferBytes - (long)m_nReadBufferPos);
  984.         memcpy(lpBuf, m_pbReadBuffer + m_nReadBufferPos, dwMoved);
  985.         m_nReadBufferPos = m_nReadBufferSize;
  986.         if (!InternetReadFile(m_hFile, lpbBuf+dwMoved, nCount-dwMoved, &dwBytes))
  987.                 AfxThrowInternetException(m_dwContext);
  988.         dwBytes += dwMoved;
  989.     }
  990.     else
  991.     {
  992.         if (m_nReadBufferPos + nCount >= m_nReadBufferBytes)
  993.         {
  994.             DWORD dwMoved = max(0, (long)m_nReadBufferBytes - (long)m_nReadBufferPos);
  995.             memcpy(lpbBuf, m_pbReadBuffer + m_nReadBufferPos, dwMoved);
  996.  
  997.             DWORD dwRead;
  998.             if (!InternetReadFile(m_hFile, m_pbReadBuffer, m_nReadBufferSize,
  999.                     &dwRead))
  1000.                 AfxThrowInternetException(m_dwContext);
  1001.             m_nReadBufferBytes = dwRead;
  1002.  
  1003.             dwRead = min(nCount - dwMoved, m_nReadBufferBytes);
  1004.             memcpy(lpbBuf + dwMoved, m_pbReadBuffer, dwRead);
  1005.             m_nReadBufferPos = dwRead;
  1006.             dwBytes = dwMoved + dwRead;
  1007.         }
  1008.         else
  1009.         {
  1010.             memcpy(lpbBuf, m_pbReadBuffer + m_nReadBufferPos, nCount);
  1011.             m_nReadBufferPos += nCount;
  1012.             dwBytes = nCount;
  1013.         }
  1014.     }
  1015.  
  1016.     return dwBytes;
  1017. }
  1018.  
  1019. void CInternetFile::Write(const void* lpBuf, UINT nCount)
  1020. {
  1021.     ASSERT_VALID(this);
  1022.     ASSERT(m_hFile != NULL);
  1023.     ASSERT(!m_bReadMode);
  1024.  
  1025.     if (m_bReadMode || m_hFile == NULL)
  1026.         AfxThrowInternetException(m_dwContext, ERROR_INVALID_HANDLE);
  1027.  
  1028.     DWORD dwBytes;
  1029.     if (m_pbWriteBuffer == NULL)
  1030.     {
  1031.         if (!InternetWriteFile(m_hFile, lpBuf, nCount, &dwBytes))
  1032.             AfxThrowInternetException(m_dwContext);
  1033.  
  1034.         if (dwBytes != nCount)
  1035.             AfxThrowInternetException(m_dwContext);
  1036.     }
  1037.     else
  1038.     {
  1039.         if ((m_nWriteBufferPos + nCount) >= m_nWriteBufferSize)
  1040.         {
  1041.             // write what is in the buffer just now
  1042.  
  1043.             if (!InternetWriteFile(m_hFile, m_pbWriteBuffer,
  1044.                     m_nWriteBufferPos, &dwBytes))
  1045.                 AfxThrowInternetException(m_dwContext);
  1046.  
  1047.             // reset the buffer position since it is now clean
  1048.  
  1049.             m_nWriteBufferPos = 0;
  1050.         }
  1051.  
  1052.         // if we can't hope to buffer the write request,
  1053.         // do it immediately ... otherwise, buffer it!
  1054.  
  1055.         if (nCount >= m_nWriteBufferSize)
  1056.         {
  1057.             if (!InternetWriteFile(m_hFile, (LPVOID) lpBuf, nCount, &dwBytes))
  1058.                 AfxThrowInternetException(m_dwContext);
  1059.         }
  1060.         else
  1061.         {
  1062.             memcpy(m_nWriteBufferPos + m_pbWriteBuffer, lpBuf, nCount);
  1063.             m_nWriteBufferPos += nCount;
  1064.         }
  1065.     }
  1066. }
  1067.  
  1068. void CInternetFile::WriteString(LPCTSTR pstr)
  1069. {
  1070.     ASSERT(!m_bReadMode);
  1071.     ASSERT(pstr != NULL);
  1072.     ASSERT_VALID(this);
  1073.     ASSERT(m_hFile != NULL);
  1074.  
  1075.     if (m_bReadMode)
  1076.         AfxThrowInternetException(m_dwContext, ERROR_INVALID_HANDLE);
  1077.  
  1078.     Write(pstr, lstrlen(pstr));
  1079. }
  1080.  
  1081. LPTSTR CInternetFile::ReadString(LPTSTR pstr, UINT nMax)
  1082. {
  1083.     ASSERT_VALID(this);
  1084.     ASSERT(m_hFile != NULL);
  1085.     DWORD dwRead;
  1086.  
  1087.     // if we're reading line-by-line, we must have a buffer
  1088.  
  1089.     if (m_pbReadBuffer == NULL)
  1090.     {
  1091.         if (!SetReadBufferSize(4096))   // arbitrary but reasonable
  1092.             return NULL;
  1093.         if (!InternetReadFile(m_hFile, m_pbReadBuffer, m_nReadBufferSize,
  1094.                 &dwRead))
  1095.             AfxThrowInternetException(m_dwContext);
  1096.         m_nReadBufferBytes = dwRead;
  1097.         m_nReadBufferPos = 0;
  1098.     }
  1099.  
  1100.     LPTSTR pstrChar = (LPTSTR) (m_pbReadBuffer + m_nReadBufferPos);
  1101.     LPTSTR pstrTarget = pstr;
  1102.  
  1103.     while (--nMax)
  1104.     {
  1105.         if (m_nReadBufferPos >= m_nReadBufferBytes)
  1106.         {
  1107.             if (!InternetReadFile(m_hFile, m_pbReadBuffer, m_nReadBufferSize,
  1108.                     &dwRead))
  1109.                 AfxThrowInternetException(m_dwContext);
  1110.             m_nReadBufferBytes = dwRead;
  1111.             if (m_nReadBufferBytes == 0)
  1112.             {
  1113.                 *pstrTarget = '\0';
  1114.                 if (pstrTarget == pstr)
  1115.                     return NULL;
  1116.                 else
  1117.                     return pstr;
  1118.             }
  1119.             else
  1120.             {
  1121.                 m_nReadBufferPos = 0;
  1122.                 pstrChar = (LPTSTR) m_pbReadBuffer;
  1123.             }
  1124.         }
  1125.  
  1126.         if (*pstrChar != '\r')
  1127.             *pstrTarget++ = *pstrChar;
  1128.  
  1129.         m_nReadBufferPos++;
  1130.         if (*pstrChar++ == '\n')
  1131.             break;
  1132.     }
  1133.  
  1134.     *pstrTarget = '\0';
  1135.     return pstr;
  1136. }
  1137.  
  1138. BOOL CInternetFile::ReadString(CString& rString)
  1139. {
  1140.     ASSERT_VALID(this);
  1141.     ASSERT(m_hFile != NULL);
  1142.  
  1143.     rString = &afxChNil;    // empty string without deallocating
  1144.     const int nMaxSize = 128;
  1145.     int nCurrentSize = nMaxSize;
  1146.  
  1147.     LPTSTR pstrPlace = rString.GetBuffer(nMaxSize);
  1148.     LPTSTR pstrResult;
  1149.     int nLen;
  1150.  
  1151.     while (1)
  1152.     {
  1153.         pstrResult = ReadString(pstrPlace, nMaxSize);
  1154.         rString.ReleaseBuffer();
  1155.  
  1156.         // if string is read completely or EOF
  1157.         if (pstrResult == NULL ||
  1158.             (nLen = lstrlen(pstrPlace)) < nMaxSize ||
  1159.             pstrPlace[nLen-1] == '\n')
  1160.             break;
  1161.  
  1162.         nLen = rString.GetLength();
  1163.         pstrPlace = rString.GetBuffer(nMaxSize + nLen) + nLen;
  1164.     }
  1165.  
  1166.     // remove '\n' from end of string if present
  1167.     pstrPlace = rString.GetBuffer(0);
  1168.     nLen = rString.GetLength();
  1169.     if (nLen != 0 && pstrPlace[nLen-1] == '\n')
  1170.         pstrPlace[nLen-1] = '\0';
  1171.     rString.ReleaseBuffer();
  1172.  
  1173.     return (pstrResult != NULL);
  1174. }
  1175.  
  1176. DWORD CInternetFile::GetLength() const
  1177. {
  1178.     ASSERT_VALID(this);
  1179.     ASSERT(m_hFile != NULL);
  1180.  
  1181.     DWORD dwRet = 0;
  1182.  
  1183.     if (m_hFile != NULL)
  1184.     {
  1185.         if (!InternetQueryDataAvailable(m_hFile, &dwRet, 0, 0))
  1186.             dwRet = 0;
  1187.     }
  1188.  
  1189.     return dwRet;
  1190. }
  1191.  
  1192. void CInternetFile::LockRange(DWORD /* dwPos */, DWORD /* dwCount */)
  1193. {
  1194.     ASSERT_VALID(this);
  1195.     ASSERT(m_hFile != NULL);
  1196.  
  1197.     AfxThrowNotSupportedException();
  1198. }
  1199.  
  1200. void CInternetFile::UnlockRange(DWORD /* dwPos */, DWORD /* dwCount */)
  1201. {
  1202.     ASSERT_VALID(this);
  1203.     ASSERT(m_hFile != NULL);
  1204.  
  1205.     AfxThrowNotSupportedException();
  1206. }
  1207.  
  1208. void CInternetFile::SetLength(DWORD)
  1209. {
  1210.     ASSERT_VALID(this);
  1211.     ASSERT(m_hFile != NULL);
  1212.  
  1213.     AfxThrowNotSupportedException();
  1214. }
  1215.  
  1216. CFile* CInternetFile::Duplicate() const
  1217. {
  1218.     ASSERT_VALID(this);
  1219.     ASSERT(m_pStream != NULL);
  1220.  
  1221.     AfxThrowNotSupportedException();
  1222.     return NULL;
  1223. }
  1224.  
  1225. #ifdef _DEBUG
  1226. void CInternetFile::AssertValid() const
  1227. {
  1228.     // Don't call CStdioFile's AsssertValid()
  1229.     CFile::AssertValid();
  1230.  
  1231.     ASSERT(m_hConnection != NULL);
  1232.  
  1233.     // make sure we really have a decent handle
  1234.     if (m_hFile != NULL)
  1235.     {
  1236.         DWORD dwResult = AfxGetInternetHandleType(m_hFile);
  1237.  
  1238.         if (IsKindOf(RUNTIME_CLASS(CHttpFile)))
  1239.         {
  1240.             ASSERT(dwResult == INTERNET_HANDLE_TYPE_HTTP_REQUEST);
  1241.         }
  1242.         else if (IsKindOf(RUNTIME_CLASS(CGopherFile)))
  1243.         {
  1244.             ASSERT(dwResult == INTERNET_HANDLE_TYPE_GOPHER_FILE ||
  1245.                 dwResult == INTERNET_HANDLE_TYPE_GOPHER_FIND_HTML ||
  1246.                 dwResult == INTERNET_HANDLE_TYPE_GOPHER_FILE_HTML ||
  1247.                 dwResult == INTERNET_HANDLE_TYPE_HTTP_REQUEST);
  1248.         }
  1249.         else if (IsKindOf(RUNTIME_CLASS(CInternetFile)))
  1250.         {
  1251.             ASSERT(dwResult == INTERNET_HANDLE_TYPE_FTP_FILE ||
  1252.                 dwResult == INTERNET_HANDLE_TYPE_FTP_FILE_HTML ||
  1253.                 dwResult == INTERNET_HANDLE_TYPE_FTP_FIND_HTML ||
  1254.                 dwResult == INTERNET_HANDLE_TYPE_HTTP_REQUEST);
  1255.         }
  1256.         else
  1257.             ASSERT(FALSE);  // some bogus object!
  1258.     }
  1259. }
  1260.  
  1261. void CInternetFile::Dump(CDumpContext& dc) const
  1262. {
  1263.     CObject::Dump(dc);
  1264.  
  1265.     dc << "\na " << GetRuntimeClass()->m_lpszClassName;
  1266.     dc << " with handle " << (UINT)m_hFile;
  1267. }
  1268. #endif
  1269.  
  1270. /////////////////////////////////////////////////////////////////////////////
  1271. // CInternetConnection
  1272.  
  1273. CInternetConnection::CInternetConnection(CInternetSession* pSession,
  1274.     LPCTSTR pstrServerName,
  1275.     INTERNET_PORT nPort /* = INTERNET_INVALID_PORT_NUMBER */,
  1276.     DWORD dwContext /* = 1 */)
  1277.     : m_strServerName(pstrServerName)
  1278. {
  1279.     ASSERT(pSession != NULL);
  1280.     ASSERT_VALID(pSession);
  1281.     ASSERT(pstrServerName != NULL);
  1282.  
  1283.     m_nPort = nPort;
  1284.     m_pSession = pSession;
  1285.     m_hConnection = NULL;
  1286.     if (dwContext == 1)
  1287.         dwContext = pSession->GetContext();
  1288.     m_dwContext = dwContext;
  1289. }
  1290.  
  1291. CInternetConnection::~CInternetConnection()
  1292. {
  1293.     if (m_hConnection != NULL)
  1294.     {
  1295. #ifdef _DEBUG
  1296.         USES_CONVERSION;
  1297.         LPCTSTR pszName = A2CT(GetRuntimeClass()->m_lpszClassName);
  1298.         TRACE3("Warning: Disconnecting %s handle %8.8X in context %8.8X at destruction.\n",
  1299.             pszName, m_hConnection, m_dwContext);
  1300. #endif
  1301.         Close();
  1302.     }
  1303. }
  1304.  
  1305. BOOL CInternetConnection::SetOption(DWORD dwOption, LPVOID lpBuffer,
  1306.     DWORD dwBufferLength, DWORD dwFlags /* = 0 */)
  1307. {
  1308.     ASSERT(dwOption >= INTERNET_FIRST_OPTION &&
  1309.         dwOption <= INTERNET_LAST_OPTION);
  1310.     ASSERT(lpBuffer != NULL);
  1311.     ASSERT(dwBufferLength != 0);
  1312.  
  1313.     // bogus flag?
  1314.     ASSERT(dwFlags == 0 || ((dwFlags & ISO_VALID_FLAGS) == dwFlags));
  1315.  
  1316.     return InternetSetOptionEx(m_hConnection, dwOption,
  1317.         lpBuffer, dwBufferLength, dwFlags);
  1318. }
  1319.  
  1320. BOOL CInternetConnection::QueryOption(DWORD dwOption, LPVOID lpBuffer,
  1321.     LPDWORD lpdwBufferLength) const
  1322. {
  1323.     ASSERT(dwOption >= INTERNET_FIRST_OPTION &&
  1324.         dwOption <= INTERNET_LAST_OPTION);
  1325.     ASSERT(lpBuffer != NULL);
  1326.     ASSERT(lpdwBufferLength != NULL);
  1327.     ASSERT(*lpdwBufferLength != 0);
  1328.  
  1329.     return InternetQueryOption(m_hConnection, dwOption,
  1330.         lpBuffer, lpdwBufferLength);
  1331. }
  1332.  
  1333. BOOL CInternetConnection::QueryOption(DWORD dwOption, DWORD& dwValue) const
  1334. {
  1335.     DWORD dwLen = sizeof(DWORD);
  1336.     return InternetQueryOption(m_hConnection, dwOption,
  1337.         &dwValue, &dwLen);
  1338. }
  1339.  
  1340. BOOL CInternetConnection::QueryOption(DWORD dwOption, CString& refString) const
  1341. {
  1342.     ASSERT(dwOption >= INTERNET_FIRST_OPTION &&
  1343.         dwOption <= INTERNET_LAST_OPTION);
  1344.  
  1345.     return _AfxQueryCStringInternetOption(m_hConnection, dwOption, refString);
  1346. }
  1347.  
  1348. void CInternetConnection::Close()
  1349. {
  1350.     if (m_hConnection != NULL)
  1351.     {
  1352.         InternetCloseHandle(m_hConnection);
  1353.         _afxSessionMap.RemoveKey(m_hConnection);
  1354.         m_hConnection = NULL;
  1355.     }
  1356. }
  1357.  
  1358. #ifdef _DEBUG
  1359. void CInternetConnection::Dump(CDumpContext& dc) const
  1360. {
  1361.     CObject::Dump(dc);
  1362.     dc << "m_hConnection = " << m_hConnection;
  1363. }
  1364.  
  1365. void CInternetConnection::AssertValid() const
  1366. {
  1367.     CObject::AssertValid();
  1368. }
  1369. #endif
  1370.  
  1371.  
  1372. /////////////////////////////////////////////////////////////////////////////
  1373. // CFtpConnection
  1374.  
  1375. CFtpConnection::~CFtpConnection()
  1376. {
  1377. }
  1378.  
  1379. CFtpConnection::CFtpConnection(CInternetSession* pSession,
  1380.     HINTERNET hConnected, LPCTSTR pstrServer, DWORD dwContext)
  1381.     : CInternetConnection(pSession, pstrServer, INTERNET_INVALID_PORT_NUMBER,
  1382.     dwContext)
  1383. {
  1384.     ASSERT(pSession != NULL);
  1385.  
  1386.     BOOL bBadType = FALSE;
  1387.     if (AfxGetInternetHandleType(hConnected) != INTERNET_HANDLE_TYPE_CONNECT_FTP)
  1388.     {
  1389.         ASSERT(FALSE);      // used the wrong handle type
  1390.         bBadType = TRUE;
  1391.     }
  1392.  
  1393.     m_strServerName = pstrServer;
  1394.     m_hConnection = hConnected;
  1395.     if (m_hConnection == NULL || bBadType)
  1396.         AfxThrowInternetException(m_dwContext, ERROR_INVALID_HANDLE);
  1397.     else
  1398.         _afxSessionMap.SetAt(m_hConnection, m_pSession);
  1399. }
  1400.  
  1401. CFtpConnection::CFtpConnection(CInternetSession* pSession,
  1402.     LPCTSTR pstrServer, LPCTSTR pstrUserName /* = NULL */,
  1403.     LPCTSTR pstrPassword /* = NULL */, DWORD dwContext /* = 0 */,
  1404.     INTERNET_PORT nPort /* = INTERNET_INVALID_PORT_NUMBER */,
  1405.     BOOL bPassive /* = FALSE */)
  1406.     : CInternetConnection(pSession, pstrServer, nPort, dwContext)
  1407. {
  1408.     ASSERT(pSession != NULL);
  1409.     ASSERT_KINDOF(CInternetSession, pSession);
  1410.  
  1411.     m_strServerName = pstrServer;
  1412.  
  1413.     m_hConnection = InternetConnect((HINTERNET) *pSession, pstrServer,
  1414.         nPort, pstrUserName, pstrPassword, INTERNET_SERVICE_FTP,
  1415.         (bPassive ? INTERNET_FLAG_PASSIVE : 0), m_dwContext);
  1416.  
  1417.     if (m_hConnection == NULL)
  1418.         AfxThrowInternetException(m_dwContext, ::GetLastError());
  1419.     else
  1420.         _afxSessionMap.SetAt(m_hConnection, m_pSession);
  1421. }
  1422.  
  1423. void CFtpConnection::Close()
  1424. {
  1425.     CInternetConnection::Close();
  1426. }
  1427.  
  1428. BOOL CFtpConnection::Remove(LPCTSTR pstrFileName)
  1429. {
  1430.     ASSERT_VALID(this);
  1431.     ASSERT(m_hConnection != NULL);
  1432.     return FtpDeleteFile(m_hConnection, pstrFileName);
  1433. }
  1434.  
  1435. BOOL CFtpConnection::Rename(LPCTSTR pstrExisting, LPCTSTR pstrNew)
  1436. {
  1437.     ASSERT_VALID(this);
  1438.     ASSERT(m_hConnection != NULL);
  1439.     return FtpRenameFile(m_hConnection, pstrExisting, pstrNew);
  1440. }
  1441.  
  1442. BOOL CFtpConnection::CreateDirectory(LPCTSTR pstrDirName)
  1443. {
  1444.     ASSERT_VALID(this);
  1445.     ASSERT(m_hConnection != NULL);
  1446.     return FtpCreateDirectory(m_hConnection, pstrDirName);
  1447. }
  1448.  
  1449. BOOL CFtpConnection::RemoveDirectory(LPCTSTR pstrDirName)
  1450. {
  1451.     ASSERT_VALID(this);
  1452.     ASSERT(m_hConnection != NULL);
  1453.     return FtpRemoveDirectory(m_hConnection, pstrDirName);
  1454. }
  1455.  
  1456. BOOL CFtpConnection::SetCurrentDirectory(LPCTSTR pstrDirName)
  1457. {
  1458.     ASSERT_VALID(this);
  1459.     ASSERT(m_hConnection != NULL);
  1460.     return FtpSetCurrentDirectory(m_hConnection, pstrDirName);
  1461. }
  1462.  
  1463. BOOL CFtpConnection::GetCurrentDirectory(LPTSTR pstrDirName,
  1464.     LPDWORD lpdwLen) const
  1465. {
  1466.     ASSERT_VALID(this);
  1467.     ASSERT(m_hConnection != NULL);
  1468.     ASSERT(pstrDirName != NULL);
  1469.  
  1470.     return FtpGetCurrentDirectory(m_hConnection, pstrDirName, lpdwLen);
  1471. }
  1472.  
  1473. BOOL CFtpConnection::GetCurrentDirectoryAsURL(CString& strDirName) const
  1474. {
  1475.     CString strDirectory;
  1476.     if (!GetCurrentDirectory(strDirectory))
  1477.         return FALSE;
  1478.  
  1479.     strDirName = szURLftp;
  1480.     strDirName += GetServerName();
  1481.  
  1482.     if (strDirectory[0] != '/')
  1483.         strDirName += '/';
  1484.  
  1485.     strDirName += strDirectory;
  1486.     return TRUE;
  1487. }
  1488.  
  1489. BOOL CFtpConnection::GetCurrentDirectoryAsURL(LPTSTR pstrName,
  1490.     LPDWORD lpdwLen) const
  1491. {
  1492.     ASSERT(lpdwLen != NULL);
  1493.     CString strTemp;
  1494.  
  1495.     if (lpdwLen == NULL || !GetCurrentDirectoryAsURL(strTemp))
  1496.         return FALSE;
  1497.  
  1498.     if (pstrName == NULL)
  1499.         *lpdwLen = strTemp.GetLength();
  1500.     else
  1501.         lstrcpyn(pstrName, (LPCTSTR) strTemp, max(0, *lpdwLen -1));
  1502.  
  1503.     return TRUE;
  1504. }
  1505.  
  1506. BOOL CFtpConnection::GetCurrentDirectory(CString& strDirName) const
  1507. {
  1508.     ASSERT_VALID(this);
  1509.     ASSERT(m_hConnection != NULL);
  1510.  
  1511.     DWORD dwLen = INTERNET_MAX_PATH_LENGTH;
  1512.     LPTSTR pstrTarget = strDirName.GetBufferSetLength(dwLen);
  1513.     BOOL bRet = FtpGetCurrentDirectory(m_hConnection, pstrTarget, &dwLen);
  1514.  
  1515.     if (bRet)
  1516.         strDirName.ReleaseBuffer(dwLen);
  1517.     else
  1518.         strDirName.ReleaseBuffer(0);
  1519.  
  1520.     return bRet;
  1521. }
  1522.  
  1523. CInternetFile* CFtpConnection::OpenFile(LPCTSTR pstrFileName,
  1524.     DWORD dwAccess /* = GENERIC_READ */,
  1525.     DWORD dwFlags /* = FTP_TRANSFER_TYPE_BINARY */,
  1526.     DWORD dwContext /* = 1 */)
  1527. {
  1528.     ASSERT_VALID(this);
  1529.     ASSERT(m_hConnection != NULL);
  1530.     ASSERT(dwAccess != (GENERIC_READ | GENERIC_WRITE));
  1531.     ASSERT(dwAccess == GENERIC_READ || dwAccess == GENERIC_WRITE);
  1532.  
  1533.     HINTERNET hFile;
  1534.     if (dwContext == 1)
  1535.         dwContext = m_dwContext;
  1536.  
  1537.     hFile = FtpOpenFile(m_hConnection, pstrFileName, dwAccess,
  1538.         dwFlags, dwContext);
  1539.     if (hFile == NULL)
  1540.         AfxThrowInternetException(dwContext);
  1541.  
  1542.     CInternetFile* pFile = new CInternetFile(hFile, pstrFileName, this,
  1543.         (dwAccess == GENERIC_READ));
  1544.     return pFile;
  1545. }
  1546.  
  1547. BOOL CFtpConnection::PutFile(LPCTSTR pstrLocalFile, LPCTSTR pstrRemoteFile,
  1548.     DWORD dwFlags /* = FTP_TRANSFER_TYPE_BINARY */,
  1549.     DWORD dwContext /* = 1 */)
  1550. {
  1551.     ASSERT_VALID(this);
  1552.     ASSERT(m_hConnection != NULL);
  1553.     ASSERT(pstrRemoteFile != NULL);
  1554.     ASSERT(pstrLocalFile != NULL);
  1555.  
  1556.     if (dwContext == 1)
  1557.         dwContext = m_dwContext;
  1558.  
  1559.     return FtpPutFile(m_hConnection, pstrLocalFile, pstrRemoteFile,
  1560.         dwFlags, dwContext);
  1561. }
  1562.  
  1563. BOOL CFtpConnection::GetFile(LPCTSTR pstrRemoteFile, LPCTSTR pstrLocalFile,
  1564.     BOOL bFailIfExists /* = TRUE */,
  1565.     DWORD dwAttributes /* = FILE_ATTRIBUTE_NORMAL */,
  1566.     DWORD dwFlags /* = FTP_TRANSFER_TYPE_BINARY */, DWORD dwContext /* = 1 */)
  1567. {
  1568.     ASSERT_VALID(this);
  1569.     ASSERT(m_hConnection != NULL);
  1570.     ASSERT(pstrRemoteFile != NULL);
  1571.     ASSERT(pstrLocalFile != NULL);
  1572.     ASSERT(!(dwAttributes & FILE_ATTRIBUTE_DIRECTORY));
  1573.  
  1574.     if (dwContext == 1)
  1575.         dwContext = m_dwContext;
  1576.  
  1577.     return FtpGetFile(m_hConnection, pstrRemoteFile, pstrLocalFile,
  1578.         bFailIfExists, dwAttributes, dwFlags, dwContext);
  1579. }
  1580.  
  1581. #ifdef _DEBUG
  1582. void CFtpConnection::Dump(CDumpContext& dc) const
  1583. {
  1584.     CInternetConnection::Dump(dc);
  1585.     dc << "\nm_strServerName = " << m_strServerName;
  1586. }
  1587.  
  1588. void CFtpConnection::AssertValid() const
  1589. {
  1590.     ASSERT(m_pSession != NULL);
  1591.     if (m_hConnection != NULL)
  1592.     {
  1593.         ASSERT(AfxGetInternetHandleType(m_hConnection)
  1594.                 == INTERNET_HANDLE_TYPE_CONNECT_FTP);
  1595.     }
  1596. }
  1597. #endif
  1598.  
  1599.  
  1600. /////////////////////////////////////////////////////////////////////////////
  1601. // CGopherConnection
  1602.  
  1603. CGopherConnection::~CGopherConnection()
  1604. {
  1605. }
  1606.  
  1607. CGopherConnection::CGopherConnection(CInternetSession* pSession,
  1608.     LPCTSTR pstrServer, LPCTSTR pstrUserName /* = NULL */,
  1609.     LPCTSTR pstrPassword /* = NULL */, DWORD dwContext /* = 0 */,
  1610.     INTERNET_PORT nPort /* = INTERNET_INVALID_PORT_NUMBER */)
  1611.     : CInternetConnection(pSession, pstrServer, nPort, dwContext)
  1612. {
  1613.     ASSERT(pSession != NULL);
  1614.     ASSERT_KINDOF(CInternetSession, pSession);
  1615.     ASSERT(pstrServer != NULL);
  1616.  
  1617.     m_hConnection = InternetConnect((HINTERNET) *pSession, pstrServer,
  1618.         nPort, pstrUserName, pstrPassword, INTERNET_SERVICE_GOPHER,
  1619.         0, m_dwContext);
  1620.  
  1621.     if (m_hConnection == NULL)
  1622.         AfxThrowInternetException(m_dwContext);
  1623.     else
  1624.         _afxSessionMap.SetAt(m_hConnection, m_pSession);
  1625. }
  1626.  
  1627. CGopherConnection::CGopherConnection(CInternetSession* pSession,
  1628.     HINTERNET hConnected, LPCTSTR pstrServer, DWORD dwContext)
  1629.     : CInternetConnection(pSession, pstrServer,
  1630.         INTERNET_INVALID_PORT_NUMBER, dwContext)
  1631. {
  1632.     ASSERT(pSession != NULL);
  1633.     ASSERT(pstrServer != NULL);
  1634.  
  1635.     BOOL bBadType = FALSE;
  1636.     if (AfxGetInternetHandleType(hConnected) != INTERNET_HANDLE_TYPE_CONNECT_GOPHER)
  1637.     {
  1638.         ASSERT(FALSE);      // used the wrong handle type
  1639.         bBadType = TRUE;
  1640.     }
  1641.  
  1642.     m_hConnection = hConnected;
  1643.     if (m_hConnection == NULL || bBadType)
  1644.         AfxThrowInternetException(m_dwContext);
  1645.     else
  1646.         _afxSessionMap.SetAt(m_hConnection, m_pSession);
  1647. }
  1648.  
  1649. CGopherLocator CGopherConnection::CreateLocator(LPCTSTR pstrLocator)
  1650. {
  1651.     CGopherLocator ret(pstrLocator, _tcslen(pstrLocator));
  1652.     return ret;
  1653. }
  1654.  
  1655. CGopherLocator CGopherConnection::CreateLocator(LPCTSTR pstrServerName,
  1656.     LPCTSTR pstrDisplayString, LPCTSTR pstrSelectorString, DWORD dwGopherType,
  1657.     INTERNET_PORT nPort /* = INTERNET_INVALID_PORT_NUMBER */)
  1658. {
  1659.     TCHAR szLocator[MAX_GOPHER_LOCATOR_LENGTH];
  1660.     DWORD dwLocLen = MAX_GOPHER_LOCATOR_LENGTH;
  1661.  
  1662.     if (!GopherCreateLocator(pstrServerName, nPort,
  1663.             pstrDisplayString, pstrSelectorString, dwGopherType,
  1664.             szLocator, &dwLocLen))
  1665.         AfxThrowInternetException(0);
  1666.  
  1667.     CGopherLocator ret(szLocator, dwLocLen);
  1668.     return ret;
  1669. }
  1670.  
  1671. CGopherLocator CGopherConnection::CreateLocator(
  1672.     LPCTSTR pstrDisplayString, LPCTSTR pstrSelectorString, DWORD dwGopherType)
  1673. {
  1674.     TCHAR szLocator[MAX_GOPHER_LOCATOR_LENGTH];
  1675.     DWORD dwLocLen = MAX_GOPHER_LOCATOR_LENGTH;
  1676.  
  1677.     if (!GopherCreateLocator(m_strServerName, m_nPort,
  1678.             pstrDisplayString, pstrSelectorString, dwGopherType,
  1679.             szLocator, &dwLocLen))
  1680.         AfxThrowInternetException(m_dwContext);
  1681.  
  1682.     CGopherLocator ret(szLocator, dwLocLen);
  1683.     return ret;
  1684. }
  1685.  
  1686.  
  1687. BOOL CGopherConnection::GetAttribute(CGopherLocator& refLocator,
  1688.     CString strRequestedAttributes, CString& strResult)
  1689. {
  1690.     DWORD dwLen = 4*MIN_GOPHER_ATTRIBUTE_LENGTH; // more than the minimum
  1691.     BOOL bRet;
  1692.     LPTSTR pstrResult = strResult.GetBuffer(dwLen);
  1693.  
  1694.     if (!GopherGetAttribute(m_hConnection, (LPCTSTR) refLocator,
  1695.             pstrResult, NULL, dwLen, &dwLen,
  1696.             NULL, m_dwContext))
  1697.     {
  1698.         bRet = FALSE;
  1699.         strResult.ReleaseBuffer(0);
  1700.     }
  1701.     else
  1702.     {
  1703.         bRet = TRUE;
  1704.         strResult.ReleaseBuffer(dwLen);
  1705.     }
  1706.  
  1707.     return bRet;
  1708. }
  1709.  
  1710. CGopherFile* CGopherConnection::OpenFile(CGopherLocator& refLocator,
  1711.     DWORD dwFlags /* = 0 */, LPCTSTR pstrView /* = NULL */,
  1712.     DWORD dwContext /* = 1 */)
  1713. {
  1714.     ASSERT_VALID(this);
  1715.     ASSERT(m_hConnection != NULL);
  1716.  
  1717.     HINTERNET hFile;
  1718.     if (dwContext == 1)
  1719.         dwContext = m_dwContext;
  1720.  
  1721.     hFile = GopherOpenFile(m_hConnection, (LPCTSTR) refLocator, pstrView,
  1722.         dwFlags, dwContext);
  1723.  
  1724.     if (hFile == NULL)
  1725.         AfxThrowInternetException(dwContext);
  1726.  
  1727.     CGopherFile* pFile = new CGopherFile(hFile, refLocator, this);
  1728.     return pFile;
  1729. }
  1730.  
  1731. void CGopherConnection::Close()
  1732. {
  1733.     CInternetConnection::Close();
  1734. }
  1735.  
  1736. #ifdef _DEBUG
  1737. void CGopherConnection::Dump(CDumpContext& dc) const
  1738. {
  1739.     CInternetConnection::Dump(dc);
  1740.     dc << "\nm_strServerName = " << m_strServerName;
  1741. }
  1742.  
  1743. void CGopherConnection::AssertValid() const
  1744. {
  1745.     ASSERT(m_pSession != NULL);
  1746.     if (m_hConnection != NULL)
  1747.     {
  1748.         ASSERT(AfxGetInternetHandleType(m_hConnection)
  1749.                 == INTERNET_HANDLE_TYPE_CONNECT_GOPHER);
  1750.     }
  1751. }
  1752. #endif
  1753.  
  1754.  
  1755. /////////////////////////////////////////////////////////////////////////////
  1756. // CHttpConnection
  1757.  
  1758. CHttpConnection::~CHttpConnection()
  1759. {
  1760. }
  1761.  
  1762. CHttpConnection::CHttpConnection(CInternetSession* pSession,
  1763.     HINTERNET hConnected, LPCTSTR pstrServer, DWORD dwContext /* = 0 */)
  1764.     : CInternetConnection(pSession, pstrServer, INTERNET_INVALID_PORT_NUMBER, dwContext)
  1765. {
  1766.     ASSERT(pSession != NULL);
  1767.     ASSERT(pstrServer != NULL);
  1768.  
  1769.     BOOL bBadType = FALSE;
  1770.     if (AfxGetInternetHandleType(hConnected) != INTERNET_HANDLE_TYPE_CONNECT_HTTP)
  1771.     {
  1772.         ASSERT(FALSE);      // used the wrong handle type
  1773.         bBadType = TRUE;
  1774.     }
  1775.  
  1776.     m_hConnection = hConnected;
  1777.     if (m_hConnection == NULL || bBadType)
  1778.         AfxThrowInternetException(m_dwContext, ERROR_INVALID_HANDLE);
  1779.     else
  1780.         _afxSessionMap.SetAt(m_hConnection, m_pSession);
  1781. }
  1782.  
  1783. CHttpConnection::CHttpConnection(CInternetSession* pSession,
  1784.     LPCTSTR pstrServer,
  1785.     INTERNET_PORT nPort /* = INTERNET_INVALID_PORT_NUMBER */,
  1786.     LPCTSTR pstrUserName /* = NULL */,
  1787.     LPCTSTR pstrPassword /* = NULL */, DWORD dwContext /* = 1 */)
  1788.     : CInternetConnection(pSession, pstrServer, nPort, dwContext)
  1789. {
  1790.     ASSERT(pSession != NULL);
  1791.     ASSERT_KINDOF(CInternetSession, pSession);
  1792.  
  1793.     m_hConnection = InternetConnect((HINTERNET) *pSession, pstrServer,
  1794.         nPort, pstrUserName, pstrPassword, INTERNET_SERVICE_HTTP,
  1795.         0, m_dwContext);
  1796.  
  1797.     if (m_hConnection == NULL)
  1798.         AfxThrowInternetException(m_dwContext);
  1799.     else
  1800.         _afxSessionMap.SetAt(m_hConnection, m_pSession);
  1801. }
  1802.  
  1803. CHttpConnection::CHttpConnection(CInternetSession* pSession,
  1804.     LPCTSTR pstrServer, DWORD dwFlags,
  1805.     INTERNET_PORT nPort /* = INTERNET_INVALID_PORT_NUMBER */,
  1806.     LPCTSTR pstrUserName /* = NULL */,
  1807.     LPCTSTR pstrPassword /* = NULL */,
  1808.     DWORD dwContext /* = 1 */)
  1809.     : CInternetConnection(pSession, pstrServer, nPort, dwContext)
  1810. {
  1811.     ASSERT(pSession != NULL);
  1812.     ASSERT_KINDOF(CInternetSession, pSession);
  1813.  
  1814.     m_hConnection = InternetConnect((HINTERNET) *pSession, pstrServer,
  1815.         nPort, pstrUserName, pstrPassword, INTERNET_SERVICE_HTTP,
  1816.         dwFlags, m_dwContext);
  1817.  
  1818.     if (m_hConnection == NULL)
  1819.         AfxThrowInternetException(m_dwContext);
  1820.     else
  1821.         _afxSessionMap.SetAt(m_hConnection, m_pSession);
  1822. }
  1823.  
  1824. void CHttpConnection::Close()
  1825. {
  1826.     CInternetConnection::Close();
  1827. }
  1828.  
  1829. CHttpFile* CHttpConnection::OpenRequest(LPCTSTR pstrVerb,
  1830.     LPCTSTR pstrObjectName, LPCTSTR pstrReferer, DWORD dwContext,
  1831.     LPCTSTR* ppstrAcceptTypes, LPCTSTR pstrVersion, DWORD dwFlags)
  1832. {
  1833.     ASSERT_VALID(this);
  1834.     ASSERT(m_hConnection != NULL);
  1835.  
  1836.     if (dwContext == 1)
  1837.         dwContext = m_dwContext;
  1838.  
  1839.     if (pstrVersion == NULL)
  1840.         pstrVersion = HTTP_VERSION;
  1841.  
  1842.     HINTERNET hFile;
  1843.     hFile = HttpOpenRequest(m_hConnection, pstrVerb, pstrObjectName,
  1844.         pstrVersion, pstrReferer, ppstrAcceptTypes, dwFlags, dwContext);
  1845.  
  1846.     CHttpFile* pRet = new CHttpFile(hFile, pstrVerb, pstrObjectName, this);
  1847.     pRet->m_dwContext = dwContext;
  1848.     return pRet;
  1849. }
  1850.  
  1851. CHttpFile* CHttpConnection::OpenRequest(int nVerb,
  1852.     LPCTSTR pstrObjectName, LPCTSTR pstrReferer, DWORD dwContext,
  1853.     LPCTSTR* ppstrAcceptTypes, LPCTSTR pstrVersion, DWORD dwFlags)
  1854. {
  1855.     ASSERT_VALID(this);
  1856.     ASSERT(m_hConnection != NULL);
  1857.  
  1858.     ASSERT(nVerb >= _HTTP_VERB_MIN && nVerb <= _HTTP_VERB_MAX);
  1859.  
  1860.     LPCTSTR pstrVerb;
  1861.     if (nVerb >= _HTTP_VERB_MIN && nVerb <= _HTTP_VERB_MAX)
  1862.         pstrVerb = szHtmlVerbs[nVerb];
  1863.     else
  1864.         pstrVerb = _T("");
  1865.  
  1866.     return OpenRequest(pstrVerb, pstrObjectName, pstrReferer,
  1867.         dwContext, ppstrAcceptTypes, pstrVersion, dwFlags);
  1868. }
  1869.  
  1870. #ifdef _DEBUG
  1871. void CHttpConnection::Dump(CDumpContext& dc) const
  1872. {
  1873.     CInternetConnection::Dump(dc);
  1874.     dc << "\nm_strServerName = " << m_strServerName;
  1875. }
  1876.  
  1877. void CHttpConnection::AssertValid() const
  1878. {
  1879.     ASSERT(m_pSession != NULL);
  1880.     if (m_hConnection != NULL)
  1881.     {
  1882.         ASSERT(AfxGetInternetHandleType(m_hConnection)
  1883.                 == INTERNET_HANDLE_TYPE_CONNECT_HTTP);
  1884.     }
  1885. }
  1886. #endif
  1887.  
  1888.  
  1889. /////////////////////////////////////////////////////////////////////////////
  1890. // CHttpFile
  1891.  
  1892. CHttpFile::CHttpFile(HINTERNET hFile, HINTERNET hSession, LPCTSTR pstrObject,
  1893.     LPCTSTR pstrServer, LPCTSTR pstrVerb, DWORD dwContext)
  1894.  : CInternetFile(hFile, hSession, pstrObject, pstrServer, dwContext, TRUE),
  1895.     m_strVerb(pstrVerb), m_strObject(pstrObject)
  1896. {
  1897.     // caller must set _afxSessionMap!
  1898.     ASSERT(pstrVerb != NULL);
  1899. }
  1900.  
  1901.  
  1902. CHttpFile::CHttpFile(HINTERNET hFile, LPCTSTR pstrVerb, LPCTSTR pstrObject,
  1903.     CHttpConnection* pConnection)
  1904.  : CInternetFile(hFile, pstrObject, pConnection, TRUE),
  1905.     m_strVerb(pstrVerb), m_strObject(pstrObject)
  1906. {
  1907.     ASSERT(pstrVerb != NULL);
  1908.     ASSERT(pstrObject != NULL);
  1909.     ASSERT(pConnection != NULL);
  1910.     ASSERT_VALID(pConnection);
  1911. }
  1912.  
  1913. CHttpFile::~CHttpFile()
  1914. {
  1915. }
  1916.  
  1917. void CHttpFile::Close()
  1918. {
  1919.     CInternetFile::Close();
  1920. }
  1921.  
  1922. DWORD CHttpFile::ErrorDlg(CWnd* pParent /* = NULL */,
  1923.     DWORD dwError /* = ERROR_INTERNET_INCORRECT_PASSWORD */,
  1924.     DWORD dwFlags /* = FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS*/,
  1925.     LPVOID* lppvData /* = NULL */)
  1926. {
  1927.     HWND hWnd;
  1928.     LPVOID lpEmpty;
  1929.     LPVOID* lppvHolder;
  1930.  
  1931.     if (lppvData == NULL)
  1932.     {
  1933.         lpEmpty = NULL;
  1934.         lppvHolder = &lpEmpty;
  1935.     }
  1936.     else
  1937.         lppvHolder = lppvData;
  1938.  
  1939.     if (pParent == NULL || pParent->m_hWnd == NULL)
  1940.         hWnd = GetDesktopWindow();
  1941.     else
  1942.         hWnd = pParent->m_hWnd;
  1943.  
  1944.     return InternetErrorDlg(hWnd, m_hFile, dwError, dwFlags, lppvHolder);
  1945. }
  1946.  
  1947. CString CHttpFile::GetVerb() const
  1948. {
  1949.     ASSERT_VALID(this);
  1950.     ASSERT(m_hFile != NULL);
  1951.  
  1952.     return m_strVerb;
  1953. }
  1954.  
  1955. CString CHttpFile::GetObject() const
  1956. {
  1957.     ASSERT_VALID(this);
  1958.     ASSERT(m_hFile != NULL);
  1959.  
  1960.     return m_strObject;
  1961. }
  1962.  
  1963. CString CHttpFile::GetFileURL() const
  1964. {
  1965.     ASSERT_VALID(this);
  1966.     ASSERT(m_hFile != NULL);
  1967.  
  1968.     CString str(szURLhttp);
  1969.     if (m_hConnection != NULL)
  1970.     {
  1971.         str += m_strServerName;
  1972.         int nLen = m_strObject.GetLength();
  1973.         if (nLen > 0)
  1974.         {
  1975.             if (m_strObject[0] != '/' && m_strObject[0] != '\\')
  1976.                 str += '/';
  1977.             str += m_strObject;
  1978.         }
  1979.     }
  1980.  
  1981.     return str;
  1982. }
  1983.  
  1984. BOOL CHttpFile::AddRequestHeaders(LPCTSTR pstrHeaders,
  1985.     DWORD dwModifiers /* = HTTP_ADDREQ_FLAG_ADD */,
  1986.     int dwHeadersLen /* = -1 */)
  1987. {
  1988.     ASSERT(dwHeadersLen == 0 || pstrHeaders != NULL);
  1989.     ASSERT_VALID(this);
  1990.     ASSERT(m_hFile != NULL);
  1991.  
  1992.     if (dwHeadersLen == -1)
  1993.         if (pstrHeaders == NULL)
  1994.             dwHeadersLen = 0;
  1995.         else
  1996.             dwHeadersLen = _tcslen(pstrHeaders);
  1997.  
  1998.     return HttpAddRequestHeaders(m_hFile, pstrHeaders, dwHeadersLen,
  1999.         dwModifiers);
  2000. }
  2001.  
  2002. BOOL CHttpFile::AddRequestHeaders(CString& str,
  2003.     DWORD dwModifiers /* = HTTP_ADDREQ_FLAG_ADD */)
  2004. {
  2005.     return AddRequestHeaders((LPCTSTR) str, dwModifiers, str.GetLength());
  2006. }
  2007.  
  2008. BOOL CHttpFile::SendRequest(LPCTSTR pstrHeaders /* = NULL */,
  2009.     DWORD dwHeadersLen /* = 0 */, LPVOID lpOptional /* = NULL */,
  2010.     DWORD dwOptionalLen /* = 0 */)
  2011. {
  2012.     ASSERT(dwOptionalLen == 0 || lpOptional != NULL);
  2013.     ASSERT(dwHeadersLen == 0 || pstrHeaders != NULL);
  2014.     ASSERT_VALID(this);
  2015.     ASSERT(m_hFile != NULL);
  2016.  
  2017.     BOOL bRet = HttpSendRequest(m_hFile,
  2018.         pstrHeaders, dwHeadersLen, lpOptional, dwOptionalLen);
  2019.  
  2020.     if (!bRet)
  2021.         AfxThrowInternetException(m_dwContext);
  2022.     return bRet;
  2023. }
  2024.  
  2025. BOOL CHttpFile::SendRequest(CString& strHeaders,
  2026.     LPVOID lpOptional /* = NULL */, DWORD dwOptionalLen /* = 0 */)
  2027. {
  2028.     ASSERT(dwOptionalLen == 0 || lpOptional != NULL);
  2029.     ASSERT_VALID(this);
  2030.     ASSERT(m_hFile != NULL);
  2031.  
  2032.     return SendRequest((LPCTSTR) strHeaders, strHeaders.GetLength(),
  2033.         lpOptional, dwOptionalLen);
  2034. }
  2035.  
  2036. BOOL CHttpFile::QueryInfo(DWORD dwInfoLevel,
  2037.     LPVOID lpvBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) const
  2038. {
  2039.     ASSERT((HTTP_QUERY_HEADER_MASK & dwInfoLevel) <= HTTP_QUERY_MAX &&
  2040.         dwInfoLevel != 0);
  2041.     ASSERT(lpvBuffer != NULL && *lpdwBufferLength > 0);
  2042.     ASSERT_VALID(this);
  2043.     ASSERT(m_hFile != NULL);
  2044.  
  2045.     return HttpQueryInfo(m_hFile, dwInfoLevel, lpvBuffer,
  2046.         lpdwBufferLength, lpdwIndex);
  2047. }
  2048.  
  2049. BOOL CHttpFile::QueryInfo(DWORD dwInfoLevel, DWORD& dwResult,
  2050.     LPDWORD lpdwIndex /* = NULL */) const
  2051. {
  2052.     DWORD dwDWSize = sizeof(DWORD);
  2053.     return QueryInfo(dwInfoLevel, &dwResult, &dwDWSize, lpdwIndex);
  2054. }
  2055.  
  2056. BOOL CHttpFile::QueryInfo(DWORD dwInfoLevel, SYSTEMTIME* pSystemTime,
  2057.     LPDWORD lpdwIndex /* = NULL */) const
  2058. {
  2059.     dwInfoLevel |= HTTP_QUERY_FLAG_SYSTEMTIME;
  2060.     DWORD dwTimeSize = sizeof(SYSTEMTIME);
  2061.     return QueryInfo(dwInfoLevel, pSystemTime, &dwTimeSize, lpdwIndex);
  2062. }
  2063.  
  2064. BOOL CHttpFile::QueryInfoStatusCode(DWORD& dwStatusCode) const
  2065. {
  2066.     ASSERT_VALID(this);
  2067.     ASSERT(m_hFile != NULL);
  2068.  
  2069.     TCHAR szBuffer[80];
  2070.     DWORD dwLen = _countof(szBuffer);
  2071.     BOOL bRet;
  2072.  
  2073.     bRet = HttpQueryInfo(m_hFile, HTTP_QUERY_STATUS_CODE,
  2074.                 szBuffer, &dwLen, NULL);
  2075.  
  2076.     if (bRet)
  2077.         dwStatusCode = (DWORD) _ttol(szBuffer);
  2078.     return bRet;
  2079. }
  2080.  
  2081. BOOL CHttpFile::QueryInfo(DWORD dwInfoLevel, CString& str,
  2082.     LPDWORD lpdwIndex) const
  2083. {
  2084.     ASSERT(dwInfoLevel <= HTTP_QUERY_MAX && dwInfoLevel >= 0);
  2085.     ASSERT_VALID(this);
  2086.     ASSERT(m_hFile != NULL);
  2087.  
  2088.     BOOL bRet;
  2089.     DWORD dwLen = 0;
  2090.  
  2091.     // ask for nothing to see how long the return really is
  2092.  
  2093.     str.Empty();
  2094.     if (HttpQueryInfo(m_hFile, dwInfoLevel, NULL, &dwLen, 0))
  2095.         bRet = TRUE;
  2096.     else
  2097.     {
  2098.         // now that we know how long it is, ask for exactly that much
  2099.         // space and really request the header from the API
  2100.  
  2101.         LPTSTR pstr = str.GetBufferSetLength(dwLen);
  2102.         bRet = HttpQueryInfo(m_hFile, dwInfoLevel, pstr, &dwLen, lpdwIndex);
  2103.         if (bRet)
  2104.             str.ReleaseBuffer(dwLen);
  2105.         else
  2106.             str.ReleaseBuffer(0);
  2107.     }
  2108.  
  2109.     return bRet;
  2110. }
  2111.  
  2112. #ifdef _DEBUG
  2113. void CHttpFile::Dump(CDumpContext& dc) const
  2114. {
  2115.     dc << "\nm_strFileName = " << m_strFileName;
  2116.     dc << "\nm_strVerb = " << m_strVerb;
  2117. }
  2118.  
  2119. void CHttpFile::AssertValid() const
  2120. {
  2121.     CInternetFile::AssertValid();
  2122. }
  2123. #endif
  2124.  
  2125. /////////////////////////////////////////////////////////////////////////////
  2126. // CGopherFile
  2127.  
  2128. CGopherFile::CGopherFile(HINTERNET hFile, CGopherLocator& refLocator,
  2129.     CGopherConnection* pConnection)
  2130.     : CInternetFile(hFile, _T(""), pConnection, TRUE),
  2131.         m_Locator(refLocator)
  2132. {
  2133.     ASSERT(pConnection != NULL);
  2134.     ASSERT_VALID(pConnection);
  2135. }
  2136.  
  2137. CGopherFile::CGopherFile(HINTERNET hFile, HINTERNET hSession,
  2138.     LPCTSTR pstrLocator, DWORD dwLocLen, DWORD dwContext)
  2139.     : CInternetFile(hFile, hSession, _T(""), _T(""), dwContext, TRUE),
  2140.         m_Locator(pstrLocator, dwLocLen)
  2141. {
  2142.     // caller muset set _afxSessionMap!
  2143. }
  2144.  
  2145. CGopherFile::~CGopherFile()
  2146. {
  2147. }
  2148.  
  2149. void CGopherFile::Close()
  2150. {
  2151.     CInternetFile::Close();
  2152. }
  2153.  
  2154. void CGopherFile::Write(const void* lpBuf, UINT nCount)
  2155. {
  2156.     UNUSED_ALWAYS(lpBuf);
  2157.     UNUSED_ALWAYS(nCount);
  2158.  
  2159.     ASSERT(FALSE);
  2160.     AfxThrowNotSupportedException();
  2161. }
  2162.  
  2163. void CGopherFile::WriteString(LPCTSTR pstr)
  2164. {
  2165.     UNUSED_ALWAYS(pstr);
  2166.  
  2167.     ASSERT(FALSE);
  2168.     AfxThrowNotSupportedException();
  2169. }
  2170.  
  2171. #ifdef _DEBUG
  2172. void CGopherFile::Dump(CDumpContext& dc) const
  2173. {
  2174.     CInternetFile::Dump(dc);
  2175. }
  2176.  
  2177. void CGopherFile::AssertValid() const
  2178. {
  2179.     CInternetFile::AssertValid();
  2180. }
  2181. #endif
  2182.  
  2183. /////////////////////////////////////////////////////////////////////////////
  2184. // CFtpFileFind
  2185.  
  2186. CFtpFileFind::CFtpFileFind(CFtpConnection* pConnection, DWORD dwContext)
  2187. {
  2188.     ASSERT(pConnection != NULL);
  2189.     ASSERT_KINDOF(CFtpConnection, pConnection);
  2190.  
  2191.     m_pConnection = pConnection;
  2192.     if (dwContext == 1)
  2193.         dwContext = pConnection->GetContext();
  2194.     m_dwContext = dwContext;
  2195.     m_chDirSeparator = '/';
  2196. }
  2197.  
  2198. CFtpFileFind::~CFtpFileFind()
  2199. {
  2200. }
  2201.  
  2202. BOOL CFtpFileFind::FindFile(LPCTSTR pstrName /* = NULL */,
  2203.     DWORD dwFlags /* = INTERNET_FLAG_RELOAD */)
  2204. {
  2205.     ASSERT(m_pConnection != NULL);
  2206.     ASSERT_VALID(m_pConnection);
  2207.  
  2208.     if (m_pConnection == NULL)
  2209.         return FALSE;
  2210.  
  2211.     Close();
  2212.     m_pNextInfo = new WIN32_FIND_DATA;
  2213.     m_bGotLast = FALSE;
  2214.  
  2215.     if (pstrName == NULL)
  2216.         pstrName = _T("*");
  2217.     _tcscpy(((LPWIN32_FIND_DATA) m_pNextInfo)->cFileName, pstrName);
  2218.  
  2219.     m_hContext = FtpFindFirstFile((HINTERNET) *m_pConnection,
  2220.         pstrName, (LPWIN32_FIND_DATA) m_pNextInfo, dwFlags, m_dwContext);
  2221.  
  2222.     if (m_hContext == NULL)
  2223.     {
  2224.         Close();
  2225.         return FALSE;
  2226.     }
  2227.  
  2228.     LPCTSTR pstrRoot = _tcspbrk(pstrName, _T("\\/"));
  2229.     CString strCWD;
  2230.     m_pConnection->GetCurrentDirectory(strCWD);
  2231.  
  2232.     if (pstrRoot == NULL)
  2233.     {
  2234.         if (m_pConnection->SetCurrentDirectory(pstrName))
  2235.         {
  2236.             m_pConnection->GetCurrentDirectory(m_strRoot);
  2237.             m_pConnection->SetCurrentDirectory(strCWD);
  2238.         }
  2239.         else
  2240.             m_strRoot = strCWD;
  2241.     }
  2242.     else
  2243.     {
  2244.         // find the last forward or backward whack
  2245.  
  2246.         int nLast;
  2247.         LPCTSTR pstrOther = _tcsrchr(pstrName, '\\');
  2248.         pstrRoot = _tcsrchr(pstrName, '/');
  2249.  
  2250.         if (pstrRoot == NULL)
  2251.             pstrRoot = pstrName;
  2252.         if (pstrOther == NULL)
  2253.             pstrOther = pstrName;
  2254.  
  2255.         if (pstrRoot >= pstrOther)
  2256.             nLast = pstrRoot - pstrName;
  2257.         else
  2258.             nLast = pstrOther - pstrName;
  2259.  
  2260.         // from the start to the last whack is the root
  2261.  
  2262.         if (nLast == 0)
  2263.             nLast++;
  2264.  
  2265.         m_strRoot = pstrName;
  2266.         m_strRoot = m_strRoot.Left(nLast);
  2267.     }
  2268.  
  2269.     return TRUE;
  2270. }
  2271.  
  2272. BOOL CFtpFileFind::FindNextFile()
  2273. {
  2274.     ASSERT(m_hContext != NULL);
  2275.     if (m_hContext == NULL)
  2276.         return FALSE;
  2277.  
  2278.     if (m_pFoundInfo == NULL)
  2279.         m_pFoundInfo = new WIN32_FIND_DATA;
  2280.  
  2281.     ASSERT_VALID(this);
  2282.     void* pTemp = m_pFoundInfo;
  2283.     m_pFoundInfo = m_pNextInfo;
  2284.     m_pNextInfo = pTemp;
  2285.  
  2286.     return InternetFindNextFile(m_hContext, m_pNextInfo);
  2287. }
  2288.  
  2289. void CFtpFileFind::CloseContext()
  2290. {
  2291.     if (m_hContext != NULL && m_hContext != INVALID_HANDLE_VALUE)
  2292.     {
  2293.         InternetCloseHandle(m_hContext);
  2294.         m_hContext = NULL;
  2295.     }
  2296.  
  2297.     return;
  2298. }
  2299.  
  2300. CString CFtpFileFind::GetFileURL() const
  2301. {
  2302.     ASSERT_VALID(this);
  2303.     ASSERT(m_hContext != NULL);
  2304.  
  2305.     CString str;
  2306.  
  2307.     if (m_hContext != NULL)
  2308.     {
  2309.         str += szURLftp;
  2310.         str += m_pConnection->GetServerName();
  2311.         str += GetFilePath();
  2312.     }
  2313.  
  2314.     return str;
  2315. }
  2316.  
  2317. #ifdef _DEBUG
  2318. void CFtpFileFind::Dump(CDumpContext& dc) const
  2319. {
  2320.     CFileFind::Dump(dc);
  2321.     dc << "m_hContext = " << m_hContext;
  2322. }
  2323.  
  2324. void CFtpFileFind::AssertValid() const
  2325. {
  2326.     CFileFind::AssertValid();
  2327. }
  2328. #endif
  2329.  
  2330.  
  2331. /////////////////////////////////////////////////////////////////////////////
  2332. // CGopherFileFind
  2333.  
  2334. CGopherFileFind::CGopherFileFind(CGopherConnection* pConnection,
  2335.     DWORD dwContext)
  2336. {
  2337.     ASSERT(pConnection != NULL);
  2338.     ASSERT_KINDOF(CGopherConnection, pConnection);
  2339.  
  2340.     m_pConnection = pConnection;
  2341.     if (dwContext == 1)
  2342.         dwContext = pConnection->GetContext();
  2343.     m_dwContext = dwContext;
  2344. }
  2345.  
  2346. CGopherFileFind::~CGopherFileFind()
  2347. {
  2348. }
  2349.  
  2350. BOOL CGopherFileFind::FindFile(LPCTSTR pstrString,
  2351.     DWORD dwFlags /* = INETERNET_FLAG_RELOAD */)
  2352. {
  2353.     Close();
  2354.  
  2355.     m_pNextInfo = new GOPHER_FIND_DATA;
  2356.     m_bGotLast = FALSE;
  2357.  
  2358.     m_hContext = GopherFindFirstFile((HINTERNET) *m_pConnection,
  2359.         NULL, pstrString,
  2360.         (GOPHER_FIND_DATA*) m_pNextInfo, dwFlags, m_dwContext);
  2361.  
  2362.     if (m_hContext == NULL)
  2363.         Close();
  2364.     return (m_hContext != NULL);
  2365. }
  2366.  
  2367. BOOL CGopherFileFind::FindFile(CGopherLocator& refLocator,
  2368.     LPCTSTR pstrString, DWORD dwFlags /* = INTERNET_FLAG_RELOAD */)
  2369. {
  2370.     Close();
  2371.  
  2372.     m_pNextInfo = new GOPHER_FIND_DATA;
  2373.     m_pFoundInfo = new GOPHER_FIND_DATA;
  2374.     m_bGotLast = FALSE;
  2375.  
  2376.     m_hContext = GopherFindFirstFile((HINTERNET) *m_pConnection,
  2377.         (LPCTSTR) refLocator, pstrString,
  2378.         (GOPHER_FIND_DATA*) m_pNextInfo, dwFlags, m_dwContext);
  2379.  
  2380.     if (m_hContext == NULL)
  2381.         Close();
  2382.     return (m_hContext != NULL);
  2383. }
  2384.  
  2385. BOOL CGopherFileFind::FindNextFile()
  2386. {
  2387.     ASSERT(m_hContext != NULL);
  2388.     if (m_hContext == NULL)
  2389.         return FALSE;
  2390.  
  2391.     if (m_pFoundInfo == NULL)
  2392.         m_pFoundInfo = new GOPHER_FIND_DATA;
  2393.  
  2394.     ASSERT_VALID(this);
  2395.     void* pTemp = m_pFoundInfo;
  2396.     m_pFoundInfo = m_pNextInfo;
  2397.     m_pNextInfo = pTemp;
  2398.  
  2399.     return InternetFindNextFile(m_hContext, m_pNextInfo);
  2400. }
  2401.  
  2402. void CGopherFileFind::CloseContext()
  2403. {
  2404.     if (m_hContext != NULL && m_hContext != INVALID_HANDLE_VALUE)
  2405.     {
  2406.         InternetCloseHandle(m_hContext);
  2407.         m_hContext = NULL;
  2408.     }
  2409.  
  2410.     return;
  2411. }
  2412.  
  2413. CString CGopherFileFind::GetFileName() const
  2414. {
  2415.     AfxThrowNotSupportedException();
  2416.     return CString();
  2417. }
  2418.  
  2419. CString CGopherFileFind::GetFilePath() const
  2420. {
  2421.     AfxThrowNotSupportedException();
  2422.     return CString();
  2423. }
  2424.  
  2425. CString CGopherFileFind::GetFileTitle() const
  2426. {
  2427.     AfxThrowNotSupportedException();
  2428.     return CString();
  2429. }
  2430.  
  2431. BOOL CGopherFileFind::IsDots() const
  2432. {
  2433.     // gophers never have dots
  2434.     return FALSE;
  2435. }
  2436.  
  2437. BOOL CGopherFileFind::GetLastWriteTime(FILETIME* pTimeStamp) const
  2438. {
  2439.     ASSERT(m_hContext != NULL);
  2440.     ASSERT(pTimeStamp != NULL);
  2441.     ASSERT_VALID(this);
  2442.  
  2443.     if (m_pFoundInfo != NULL && pTimeStamp != NULL)
  2444.     {
  2445.         *pTimeStamp = ((LPGOPHER_FIND_DATA) m_pFoundInfo)->LastModificationTime;
  2446.         return TRUE;
  2447.     }
  2448.     else
  2449.         return FALSE;
  2450. }
  2451.  
  2452. BOOL CGopherFileFind::GetLastAccessTime(FILETIME* pTimeStamp) const
  2453. {
  2454.     return GetLastWriteTime(pTimeStamp);
  2455. }
  2456.  
  2457. BOOL CGopherFileFind::GetCreationTime(FILETIME* pTimeStamp) const
  2458. {
  2459.     return GetLastWriteTime(pTimeStamp);
  2460. }
  2461.  
  2462. BOOL CGopherFileFind::GetLastWriteTime(CTime& refTime) const
  2463. {
  2464.     ASSERT(m_hContext != NULL);
  2465.     ASSERT_VALID(this);
  2466.  
  2467.     if (m_pFoundInfo != NULL)
  2468.     {
  2469.         refTime = CTime(((LPGOPHER_FIND_DATA) m_pFoundInfo)->LastModificationTime);
  2470.         return TRUE;
  2471.     }
  2472.     else
  2473.         return FALSE;
  2474. }
  2475.  
  2476. BOOL CGopherFileFind::GetCreationTime(CTime& refTime) const
  2477. {
  2478.     return GetLastWriteTime(refTime);
  2479. }
  2480.  
  2481. BOOL CGopherFileFind::GetLastAccessTime(CTime& refTime) const
  2482. {
  2483.     return GetLastWriteTime(refTime);
  2484. }
  2485.  
  2486.  
  2487. CString CGopherFileFind::GetFileURL() const
  2488. {
  2489.     AfxThrowNotSupportedException();
  2490.     return CString();
  2491. }
  2492.  
  2493. CString CGopherFileFind::GetRoot() const
  2494. {
  2495.     AfxThrowNotSupportedException();
  2496.     return CString();
  2497. }
  2498.  
  2499. CGopherLocator CGopherFileFind::GetLocator() const
  2500. {
  2501.     ASSERT_VALID(this);
  2502.     ASSERT(m_pConnection != NULL && m_hContext != NULL);
  2503.  
  2504.     return m_pConnection->CreateLocator(
  2505.         ((LPGOPHER_FIND_DATA) m_pFoundInfo)->Locator);
  2506. }
  2507.  
  2508. CString CGopherFileFind::GetScreenName() const
  2509. {
  2510.     ASSERT_VALID(this);
  2511.     ASSERT(m_hContext != NULL);
  2512.  
  2513.     CString str;
  2514.  
  2515.     if (m_pFoundInfo != NULL)
  2516.         str = ((LPGOPHER_FIND_DATA) m_pFoundInfo)->DisplayString;
  2517.  
  2518.     return str;
  2519. }
  2520.  
  2521. DWORD CGopherFileFind::GetLength() const
  2522. {
  2523.     ASSERT_VALID(this);
  2524.  
  2525.     if (m_pFoundInfo != NULL)
  2526.         return ((LPGOPHER_FIND_DATA) m_pFoundInfo)->SizeLow;
  2527.     else
  2528.         return 0;
  2529. }
  2530.  
  2531. #if defined(_X86_) || defined(_ALPHA_)
  2532. __int64 CGopherFileFind::GetLength64() const
  2533. {
  2534.     ASSERT_VALID(this);
  2535.  
  2536.     if (m_pFoundInfo != NULL)
  2537.         return ((LPGOPHER_FIND_DATA) m_pFoundInfo)->SizeLow +
  2538.                 (((LPGOPHER_FIND_DATA) m_pFoundInfo)->SizeHigh << 32);
  2539.     else
  2540.         return 0;
  2541. }
  2542. #endif
  2543.  
  2544. #ifdef _DEBUG
  2545. void CGopherFileFind::Dump(CDumpContext& dc) const
  2546. {
  2547.     CFileFind::Dump(dc);
  2548.     dc << "m_hContext = " << m_hContext;
  2549. }
  2550.  
  2551. void CGopherFileFind::AssertValid() const
  2552. {
  2553.     CFileFind::AssertValid();
  2554. }
  2555. #endif
  2556.  
  2557.  
  2558. /////////////////////////////////////////////////////////////////////////////
  2559. // CGopherLocator
  2560.  
  2561. CGopherLocator::CGopherLocator(LPCTSTR pstrLocator, DWORD dwLocLen)
  2562. {
  2563.     LPTSTR pstr = m_Locator.GetBufferSetLength(dwLocLen);
  2564.     memcpy(pstr, pstrLocator, dwLocLen);
  2565.     m_Locator.ReleaseBuffer(dwLocLen);
  2566.     m_dwBufferLength = dwLocLen;
  2567. }
  2568.  
  2569. CGopherLocator::~CGopherLocator()
  2570. {
  2571. }
  2572.  
  2573. /////////////////////////////////////////////////////////////////////////////
  2574. // exception handling
  2575.  
  2576. void AFXAPI AfxThrowInternetException(DWORD dwContext, DWORD dwError /* = 0 */)
  2577. {
  2578.     if (dwError == 0)
  2579.         dwError = ::GetLastError();
  2580.  
  2581.     CInternetException* pException = new CInternetException(dwError);
  2582.     pException->m_dwContext = dwContext;
  2583.  
  2584.     TRACE1("Warning: throwing CInternetException for error %d\n", dwError);
  2585.     THROW(pException);
  2586. }
  2587.  
  2588.  
  2589. BOOL CInternetException::GetErrorMessage(LPTSTR pstrError, UINT nMaxError,
  2590.         PUINT pnHelpContext)
  2591. {
  2592.     ASSERT(pstrError != NULL && AfxIsValidString(pstrError, nMaxError));
  2593.  
  2594.     if (pnHelpContext != NULL)
  2595.         *pnHelpContext = 0;
  2596.  
  2597. #ifndef _MAC
  2598.     LPTSTR lpBuffer;
  2599.     BOOL bRet = TRUE;
  2600.  
  2601.     HINSTANCE hWinINetLibrary;
  2602. #ifdef _AFXDLL
  2603.     hWinINetLibrary = _afxExtDllState->m_hInstInternet;
  2604. #else
  2605.     hWinINetLibrary = ::LoadLibraryA("WININET.DLL");
  2606. #endif
  2607.  
  2608.     if (hWinINetLibrary == NULL ||
  2609.         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  2610.             hWinINetLibrary, m_dwError,
  2611.             MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
  2612.             (LPTSTR) &lpBuffer, 0, NULL) == 0)
  2613.     {
  2614.         // it failed! try Windows...
  2615.  
  2616.         bRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  2617.             NULL,  m_dwError,
  2618.             MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
  2619.             (LPTSTR) &lpBuffer, 0, NULL);
  2620.     }
  2621.  
  2622.     if (bRet == FALSE)
  2623.         *pstrError = '\0';
  2624.     else
  2625.     {
  2626.         if (m_dwError == ERROR_INTERNET_EXTENDED_ERROR)
  2627.         {
  2628.             LPTSTR lpExtended;
  2629.             DWORD dwLength = 0;
  2630.             DWORD dwError;
  2631.  
  2632.             // find the length of the error
  2633.             if (!InternetGetLastResponseInfo(&dwError, NULL, &dwLength) &&
  2634.                 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  2635.             {
  2636.                 lpExtended = (LPTSTR) LocalAlloc(LPTR, dwLength);
  2637.                 InternetGetLastResponseInfo(&dwError, lpExtended, &dwLength);
  2638.                 lstrcpyn(pstrError, lpExtended, nMaxError);
  2639.                 pstrError += dwLength;
  2640.                 nMaxError -= dwLength;
  2641.                 if (nMaxError < 0)
  2642.                     nMaxError = 0;
  2643.                 LocalFree(lpExtended);
  2644.             }
  2645.             else
  2646.                 TRACE0("Warning: Extended error reported with no response info\n");
  2647.             bRet = TRUE;
  2648.         }
  2649.         else
  2650.         {
  2651.             lstrcpyn(pstrError, lpBuffer, nMaxError);
  2652.             bRet = TRUE;
  2653.         }
  2654.  
  2655.         LocalFree(lpBuffer);
  2656.     }
  2657.  
  2658. #ifndef _AFXDLL
  2659.     ::FreeLibrary(hWinINetLibrary);
  2660. #endif
  2661.     return bRet;
  2662.  
  2663. #else
  2664.     UNUSED_ALWAYS(nMaxError);
  2665.     *pstrError = '\0';
  2666.     return FALSE;
  2667. #endif // _MAC
  2668. }
  2669.  
  2670. CInternetException::CInternetException(DWORD dwError)
  2671. {
  2672.     m_dwError = dwError;
  2673. }
  2674.  
  2675. CInternetException::~CInternetException()
  2676. {
  2677. }
  2678.  
  2679. #ifdef _DEBUG
  2680. void CInternetException::Dump(CDumpContext& dc) const
  2681. {
  2682.     CObject::Dump(dc);
  2683.  
  2684.     dc << "m_dwError = " << m_dwError;
  2685.     dc << "\nm_dwContext = " << m_dwContext;
  2686. }
  2687. #endif
  2688.  
  2689. /////////////////////////////////////////////////////////////////////////////
  2690. // Inline function declarations expanded out-of-line
  2691.  
  2692. #ifndef _AFX_ENABLE_INLINES
  2693.  
  2694. // expand inlines for OLE dialog APIs
  2695. static char _szAfxInetInl[] = "afxinet.inl";
  2696. #undef THIS_FILE
  2697. #define THIS_FILE _szAfxInetInl
  2698. #define _AFXINET_INLINE
  2699. #include "afxinet.inl"
  2700.  
  2701. #endif //!_AFX_ENABLE_INLINES
  2702.  
  2703. /////////////////////////////////////////////////////////////////////////////
  2704. // Pre-startup code
  2705.  
  2706. #ifdef AFX_INIT_SEG
  2707. #pragma code_seg(AFX_INIT_SEG)
  2708. #endif
  2709.  
  2710. IMPLEMENT_DYNAMIC(CInternetException, CException)
  2711. IMPLEMENT_DYNAMIC(CInternetFile, CStdioFile)
  2712. IMPLEMENT_DYNAMIC(CHttpFile, CInternetFile)
  2713. IMPLEMENT_DYNAMIC(CGopherFile, CInternetFile)
  2714. IMPLEMENT_DYNAMIC(CInternetSession, CObject)
  2715. IMPLEMENT_DYNAMIC(CInternetConnection, CObject)
  2716. IMPLEMENT_DYNAMIC(CFtpConnection, CInternetConnection)
  2717. IMPLEMENT_DYNAMIC(CHttpConnection, CInternetConnection)
  2718. IMPLEMENT_DYNAMIC(CGopherConnection, CInternetConnection)
  2719. IMPLEMENT_DYNAMIC(CFtpFileFind, CFileFind)
  2720. IMPLEMENT_DYNAMIC(CGopherFileFind, CFileFind)
  2721.  
  2722. #pragma warning(disable: 4074)
  2723. #pragma init_seg(compiler)
  2724.  
  2725. CSessionMapPtrToPtr _afxSessionMap;
  2726.