home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / Basic / Visual Basic.60 / COMMON / TOOLS / VCM / VCM.MDB / VcmComponentContainer / 07_Cabinet / TEAR.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1998-05-18  |  9.7 KB  |  377 lines

  1. // tear.cpp : implements the TEAR console application
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1997-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include <afx.h>
  14. #include <afxwin.h>
  15. #include <afxinet.h>
  16. #include "tear.h"
  17.  
  18. #include <iostream.h>
  19. #include <stdlib.h>
  20.  
  21. /////////////////////////////////////////////////////////////////////////////
  22. // Globals
  23.  
  24. LPCTSTR pszURL = NULL;
  25. BOOL    bStripMode = FALSE;
  26. BOOL    bProgressMode = FALSE;
  27. DWORD   dwAccessType = PRE_CONFIG_INTERNET_ACCESS;
  28.  
  29. DWORD dwHttpRequestFlags =
  30.     INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_AUTO_REDIRECT;
  31.  
  32. const TCHAR szHeaders[] =
  33.     _T("Accept: text/*\r\nUser-Agent: MFC_Tear_Sample\r\n");
  34.  
  35. /////////////////////////////////////////////////////////////////////////////
  36. // CTearSession object
  37.  
  38. // TEAR wants to use its own derivative of the CInternetSession class
  39. // just so it can implement an OnStatusCallback() override.
  40.  
  41. CTearSession::CTearSession(LPCTSTR pszAppName, int nMethod)
  42.     : CInternetSession(pszAppName, 1, nMethod)
  43. {
  44. }
  45.  
  46. void CTearSession::OnStatusCallback(DWORD /* dwContext */, DWORD dwInternetStatus,
  47.     LPVOID /* lpvStatusInfomration */, DWORD /* dwStatusInformationLen */)
  48. {
  49.     if (!bProgressMode)
  50.         return;
  51.  
  52.     if (dwInternetStatus == INTERNET_STATUS_CONNECTED_TO_SERVER)
  53.         cerr << _T("Connection made!") << endl;
  54. }
  55.  
  56. /////////////////////////////////////////////////////////////////////////////
  57. // CTearException -- used if something goes wrong for us
  58.  
  59. // TEAR will throw its own exception type to handle problems it might
  60. // encounter while fulfilling the user's request.
  61.  
  62. IMPLEMENT_DYNCREATE(CTearException, CException)
  63.  
  64. CTearException::CTearException(int nCode)
  65.     : m_nErrorCode(nCode)
  66. {
  67. }
  68.  
  69. void ThrowTearException(int nCode)
  70. {
  71.     CTearException* pEx = new CTearException(nCode);
  72.     throw pEx;
  73. }
  74.  
  75. /////////////////////////////////////////////////////////////////////////////
  76. // Routines
  77.  
  78. void ShowBanner()
  79. {
  80.     cerr << _T("TEAR - Tear a Page Off the Internet!") << endl;
  81.     cerr << _T("Version 4.2 - Copyright (C) Microsoft Corp 1998") << endl;
  82.     cerr << endl;
  83. }
  84.  
  85. void ShowUsage()
  86. {
  87.     cerr << _T("Usage:  TEAR [options] <URL>") << endl << endl;
  88.     cerr << _T("\t<URL> points at a HTTP resource") << endl;
  89.     cerr << _T("\t[options] are any of:") << endl;
  90.     cerr << _T("\t\t/F force reload of requested page") << endl;
  91.     cerr << _T("\t\t/P show detailed progress information") << endl;
  92.     cerr << _T("\t\t/S strip HTML tags from stream") << endl << endl;
  93.     cerr << _T("\t\t/L use local Internet access") << endl;
  94.     cerr << _T("\t\t/D use pre-configured Internet access (default)") << endl;
  95.  
  96.     cerr << endl;
  97.     exit(1);
  98. }
  99.  
  100. // ParseOptions() looks for options on the command line and sets global
  101. // flags so the rest of the program knows about them.  ParseOptions()
  102. // also initializes pszURL to point at the URL the user wanted.
  103.  
  104. BOOL ParseOptions(int argc, char* argv[])
  105. {
  106.     int nIndex;
  107.     for (nIndex = 1; nIndex < argc; nIndex++)
  108.     {
  109.         // an option or a URL?
  110.  
  111.         if (*argv[nIndex] == '-' || *argv[nIndex] == '/')
  112.         {
  113.             if (argv[nIndex][1] == 'D' || argv[nIndex][1] == 'd')
  114.                 dwAccessType = PRE_CONFIG_INTERNET_ACCESS;
  115.             else if (argv[nIndex][1] == 'L' || argv[nIndex][1] == 'l')
  116.                 dwAccessType = LOCAL_INTERNET_ACCESS;
  117.             else if (argv[nIndex][1] == 'S' || argv[nIndex][1] == 's')
  118.                 bStripMode = TRUE;
  119.             else if (argv[nIndex][1] == 'P' || argv[nIndex][1] == 'p')
  120.                 bProgressMode = TRUE;
  121.             else if (argv[nIndex][1] == 'F' || argv[nIndex][1] == 'f')
  122.                 dwHttpRequestFlags |= INTERNET_FLAG_RELOAD;
  123.             else
  124.             {
  125.                 cerr << _T("Error: unrecognized option: ") << argv[nIndex] << endl;
  126.                 return FALSE;
  127.             }
  128.         }
  129.         else
  130.         {
  131.         // can't have too many URLs
  132.  
  133.         if (pszURL != NULL)
  134.         {
  135.             cerr << _T("Error: can only specify one URL!") << endl;
  136.             return FALSE;
  137.         }
  138.         else
  139.             pszURL = argv[nIndex];
  140.         }
  141.     }
  142.  
  143.     return TRUE;
  144. }
  145.  
  146. // StripTags() rips through a buffer and removes HTML tags from it.
  147. // The function uses a static variable to remember its state in case
  148. // a HTML tag spans a buffer boundary.
  149.  
  150. void StripTags(LPTSTR pszBuffer)
  151. {
  152.     static BOOL bInTag = FALSE;
  153.     LPTSTR pszSource = pszBuffer;
  154.     LPTSTR pszDest = pszBuffer;
  155.  
  156.     while (*pszSource != '\0')
  157.     {
  158.         if (bInTag)
  159.         {
  160.             if (*pszSource == '>')
  161.                 bInTag = FALSE;
  162.             pszSource++;
  163.         }
  164.         else
  165.         {
  166.             if (*pszSource == '<')
  167.                 bInTag = TRUE;
  168.             else
  169.             {
  170.                 *pszDest = *pszSource;
  171.                 pszDest++;
  172.             }
  173.             pszSource++;
  174.         }
  175.     }
  176.     *pszDest = '\0';
  177. }
  178.  
  179. /////////////////////////////////////////////////////////////////////////////
  180. // The main() Thang
  181.  
  182. int main(int argc, char* argv[])
  183. {
  184.     ShowBanner();
  185.  
  186.     if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
  187.     {
  188.         cerr << _T("MFC Failed to initialize.\n");
  189.         return 1;
  190.     }
  191.  
  192.     if (argc < 2 || !ParseOptions(argc, argv) || pszURL == NULL)
  193.         ShowUsage();
  194.  
  195.     int nRetCode = 0;
  196.  
  197.     CTearSession session(_T("TEAR - MFC Sample App"), dwAccessType);
  198.     CHttpConnection* pServer = NULL;
  199.     CHttpFile* pFile = NULL;
  200.     try
  201.     {
  202.         // check to see if this is a reasonable URL
  203.  
  204.         CString strServerName;
  205.         CString strObject;
  206.         INTERNET_PORT nPort;
  207.         DWORD dwServiceType;
  208.  
  209.         if (!AfxParseURL(pszURL, dwServiceType, strServerName, strObject, nPort) ||
  210.             dwServiceType != INTERNET_SERVICE_HTTP)
  211.         {
  212.             cerr << _T("Error: can only use URLs beginning with http://") << endl;
  213.             ThrowTearException(1);
  214.         }
  215.  
  216.         if (bProgressMode)
  217.         {
  218.             cerr << _T("Opening Internet...");
  219.             VERIFY(session.EnableStatusCallback(TRUE));
  220.         }
  221.  
  222.         pServer = session.GetHttpConnection(strServerName, nPort);
  223.  
  224.         pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET,
  225.             strObject, NULL, 1, NULL, NULL, dwHttpRequestFlags);
  226.         pFile->AddRequestHeaders(szHeaders);
  227.         pFile->SendRequest();
  228.  
  229.         DWORD dwRet;
  230.         pFile->QueryInfoStatusCode(dwRet);
  231.  
  232.         // if access was denied, prompt the user for the password
  233.  
  234.         if (dwRet == HTTP_STATUS_DENIED)
  235.         {
  236.             DWORD dwPrompt;
  237.             dwPrompt = pFile->ErrorDlg(NULL, ERROR_INTERNET_INCORRECT_PASSWORD,
  238.                 FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, NULL);
  239.  
  240.             // if the user cancelled the dialog, bail out
  241.  
  242.             if (dwPrompt != ERROR_INTERNET_FORCE_RETRY)
  243.             {
  244.                 cerr << _T("Access denied: Invalid password\n");
  245.                 ThrowTearException(1);
  246.             }
  247.  
  248.             pFile->SendRequest();
  249.             pFile->QueryInfoStatusCode(dwRet);
  250.         }
  251.  
  252.         CString strNewLocation;
  253.         pFile->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF, strNewLocation);
  254.  
  255.         // were we redirected?
  256.         // these response status codes come from WININET.H
  257.  
  258.         if (dwRet == HTTP_STATUS_MOVED ||
  259.             dwRet == HTTP_STATUS_REDIRECT ||
  260.             dwRet == HTTP_STATUS_REDIRECT_METHOD)
  261.         {
  262.             CString strNewLocation;
  263.             pFile->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF, strNewLocation);
  264.  
  265.             int nPlace = strNewLocation.Find(_T("Location: "));
  266.             if (nPlace == -1)
  267.             {
  268.                 cerr << _T("Error: Site redirects with no new location") << endl;
  269.                 ThrowTearException(2);
  270.             }
  271.  
  272.             strNewLocation = strNewLocation.Mid(nPlace + 10);
  273.             nPlace = strNewLocation.Find('\n');
  274.             if (nPlace > 0)
  275.                 strNewLocation = strNewLocation.Left(nPlace);
  276.  
  277.             // close up the redirected site
  278.  
  279.             pFile->Close();
  280.             delete pFile;
  281.             pServer->Close();
  282.             delete pServer;
  283.  
  284.             if (bProgressMode)
  285.             {
  286.                 cerr << _T("Caution: redirected to ");
  287.                 cerr << (LPCTSTR) strNewLocation << endl;
  288.             }
  289.  
  290.             // figure out what the old place was
  291.             if (!AfxParseURL(strNewLocation, dwServiceType, strServerName, strObject, nPort))
  292.             {
  293.                 cerr << _T("Error: the redirected URL could not be parsed.") << endl;
  294.                 ThrowTearException(2);
  295.             }
  296.  
  297.             if (dwServiceType != INTERNET_SERVICE_HTTP)
  298.             {
  299.                 cerr << _T("Error: the redirected URL does not reference a HTTP resource.") << endl;
  300.                 ThrowTearException(2);
  301.             }
  302.  
  303.             // try again at the new location
  304.             pServer = session.GetHttpConnection(strServerName, nPort);
  305.             pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET,
  306.                 strObject, NULL, 1, NULL, NULL, dwHttpRequestFlags);
  307.             pFile->AddRequestHeaders(szHeaders);
  308.             pFile->SendRequest();
  309.  
  310.             pFile->QueryInfoStatusCode(dwRet);
  311.             if (dwRet != HTTP_STATUS_OK)
  312.             {
  313.                 cerr << _T("Error: Got status code ") << dwRet << endl;
  314.                 ThrowTearException(2);
  315.             }
  316.         }
  317.  
  318.         cerr << _T("Status Code is ") << dwRet << endl;
  319.  
  320.         TCHAR sz[1024];
  321.         while (pFile->ReadString(sz, 1023))
  322.         {
  323.             if (bStripMode)
  324.                 StripTags(sz);
  325.             cout << sz;
  326.         }
  327.  
  328.     // NOTE: Since HTTP servers normally spit back plain text, the
  329.     // above code (which reads line by line) is just fine.  However,
  330.     // other data sources (eg, FTP servers) might provide binary data
  331.     // which should be handled a buffer at a time, like this:
  332.  
  333. #if 0
  334.         while (nRead > 0)
  335.         {
  336.             sz[nRead] = '\0';
  337.             if (bStripMode)
  338.                 StripTags(sz);
  339.             cout << sz;
  340.             nRead = pFile->Read(sz, 1023);
  341.         }
  342. #endif
  343.  
  344.         pFile->Close();
  345.         pServer->Close();
  346.     }
  347.     catch (CInternetException* pEx)
  348.     {
  349.         // catch errors from WinINet
  350.  
  351.         TCHAR szErr[1024];
  352.         pEx->GetErrorMessage(szErr, 1024);
  353.  
  354.         cerr << _T("Error: (") << pEx->m_dwError << _T(") ");
  355.         cerr << szErr << endl;
  356.  
  357.         nRetCode = 2;
  358.         pEx->Delete();
  359.     }
  360.     catch (CTearException* pEx)
  361.     {
  362.         // catch things wrong with parameters, etc
  363.  
  364.         nRetCode = pEx->m_nErrorCode;
  365.         TRACE1("Error: Exiting with CTearException(%d)\n", nRetCode);
  366.         pEx->Delete();
  367.     }
  368.  
  369.     if (pFile != NULL)
  370.         delete pFile;
  371.     if (pServer != NULL)
  372.         delete pServer;
  373.     session.Close();
  374.  
  375.     return nRetCode;
  376. }
  377.