home *** CD-ROM | disk | FTP | other *** search
/ PC World 2003 June / PCWorld_2003-06_cd.bin / KOMUNIK / MIRRORIT / SRC / HTTPSOCKET.CPP < prev    next >
C/C++ Source or Header  |  1999-01-06  |  29KB  |  1,394 lines

  1. // HTTPSocket.cpp : implementation file
  2. //
  3.  
  4. #include "stdafx.h"
  5. #include "MirrorIt.h"
  6. #include "Session.h"
  7. #include "HTTPSocket.h"
  8. #include "URL.h"
  9. #include <stdio.h>
  10.  
  11. #ifdef _DEBUG
  12. #define new DEBUG_NEW
  13. #undef THIS_FILE
  14. static char THIS_FILE[] = __FILE__;
  15. #endif
  16.  
  17. const unsigned long crc_table[] = {
  18.   0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
  19.   0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
  20.   0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
  21.   0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
  22.   0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
  23.   0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
  24.   0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
  25.   0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
  26.   0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
  27.   0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
  28.   0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
  29.   0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
  30.   0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
  31.   0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
  32.   0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
  33.   0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
  34.   0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
  35.   0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
  36.   0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
  37.   0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
  38.   0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
  39.   0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
  40.   0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
  41.   0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
  42.   0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
  43.   0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
  44.   0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
  45.   0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
  46.   0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
  47.   0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
  48.   0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
  49.   0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
  50.   0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
  51.   0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
  52.   0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
  53.   0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
  54.   0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
  55.   0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
  56.   0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
  57.   0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
  58.   0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
  59.   0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
  60.   0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
  61.   0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
  62.   0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
  63.   0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
  64.   0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
  65.   0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
  66.   0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
  67.   0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
  68.   0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
  69.   0x2d02ef8dL
  70. };
  71.  
  72. #define CRC32(c, b) (crc_table[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
  73. #define DO1(buf)  crc = CRC32(crc, *buf++)
  74. #define DO2(buf)  DO1(buf); DO1(buf)
  75. #define DO4(buf)  DO2(buf); DO2(buf)
  76. #define DO8(buf)  DO4(buf); DO4(buf)
  77.  
  78. unsigned long crc32(unsigned long crc, const unsigned char *buf, int len)
  79. {
  80.   if (!buf)
  81.   {
  82.       return 0L;
  83.   }
  84.  
  85.   crc = crc ^ 0xffffffffL;
  86.   if (len) do {
  87.     DO1(buf);
  88.   } while (--len);
  89.   return crc ^ 0xffffffffL;
  90. }
  91.  
  92. /////////////////////////////////////////////////////////////////////////////
  93. // CHTTPSocket
  94.  
  95. CHTTPSocket::CHTTPSocket()
  96. {
  97.     m_Header.RemoveAll();
  98.     m_sBlockRemain.Empty();
  99.     htmltemp.RemoveAll();
  100.     links = NULL;
  101.     m_bFirstLine = TRUE;
  102.     m_bConnect = FALSE;
  103.     m_bSent = FALSE;
  104.     m_bClose = FALSE;
  105.     m_bInHeader = TRUE;
  106.     m_buf.SetSize(1024);
  107.     m_request.Empty();
  108.     m_requestindex = 0;
  109.     m_progress = NULL;
  110.     m_bDocument = FALSE;
  111.     m_filestatus = 0;
  112.     m_bError = FALSE;
  113.     m_bFileInited = FALSE;
  114.     m_bRedirect = FALSE;
  115.     m_iCode = 0;
  116.     m_recv = FALSE;
  117. }
  118.  
  119. CHTTPSocket::~CHTTPSocket()
  120. {
  121.     if (m_filestatus == 1)
  122.     {
  123.         m_File.Write(htmltemp.GetData(), htmltemp.GetSize());
  124.     }
  125.  
  126.     if (m_filestatus > 0)
  127.     {
  128.         CString filename = m_File.GetFilePath();
  129.         m_File.Close();
  130.         if (m_filestatus == 2)
  131.         {
  132.             DeleteFile((LPCSTR)filename);
  133.         }
  134.     }
  135. }
  136.  
  137.  
  138. // Do not edit the following lines, which are needed by ClassWizard.
  139. #if 0
  140. BEGIN_MESSAGE_MAP(CHTTPSocket, CAsyncSocket)
  141.     //{{AFX_MSG_MAP(CHTTPSocket)
  142.     //}}AFX_MSG_MAP
  143. END_MESSAGE_MAP()
  144. #endif    // 0
  145.  
  146. /////////////////////////////////////////////////////////////////////////////
  147. // CHTTPSocket member functions
  148.  
  149. void CHTTPSocket::OnClose(int nErrorCode) 
  150. {
  151.     m_bClose = TRUE;
  152.     
  153.     CAsyncSocket::OnClose(nErrorCode);
  154. }
  155.  
  156. void CHTTPSocket::OnConnect(int nErrorCode) 
  157. {
  158.     m_bConnect = TRUE;
  159.     
  160.     CAsyncSocket::OnConnect(nErrorCode);
  161. }
  162.  
  163. void CHTTPSocket::OnReceive(int nErrorCode) 
  164. {
  165. /*    if (!m_recv)
  166.     {
  167.         AddLog("nem kellett volna csomagot kapni");
  168.     }*/
  169.     //AsyncSelect(0);
  170.     int nBytes = Receive(m_buf.GetData(), m_buf.GetSize());
  171.     if (nBytes != SOCKET_ERROR)
  172.     {
  173.         //!!!!!!!!!!!!!!!!!!!!!!!!!!!
  174. //        m_bDocument = (m_filename.Find(".htm") != -1);
  175.         if (m_bInHeader)
  176.         {
  177.             int headersize = ProcessHeader(nBytes);
  178.             if (headersize < nBytes)
  179.             {
  180.                 m_bInHeader = FALSE;
  181.                 OutputData(m_buf.GetData() + headersize, nBytes - headersize);
  182.             }
  183.         }
  184.         else
  185.         {
  186.             OutputData(m_buf.GetData(), nBytes);
  187. /*            BYTE sep = '|';
  188.             OutputData(&sep, 1);*/
  189.         }
  190.     }
  191.     else
  192.         nBytes = GetLastError();
  193.     //AsyncSelect(FD_WRITE | FD_CLOSE);
  194. }
  195.  
  196. void CHTTPSocket::OnSend(int nErrorCode) 
  197. {
  198.     if (m_requestindex < m_request.GetLength())
  199.     {
  200.         int nBytes = Send((LPCSTR)m_request + m_requestindex, max(0, m_request.GetLength() - m_requestindex));
  201.         if (nBytes != SOCKET_ERROR)
  202.         {
  203.             m_requestindex += nBytes;
  204.         }
  205.         else
  206.         {
  207.             nBytes = GetLastError();
  208.         }
  209.     }
  210.     m_bSent = m_requestindex >= m_request.GetLength();
  211. }
  212.  
  213. void CHTTPSocket::SendRequest(CString request)
  214. {
  215.     if (!m_progress)
  216.     {
  217.         m_progress -> SetRange(0, 100);
  218.     }
  219.     m_iCode = -1;
  220. //    m_bFirstLine = TRUE;
  221.     m_bProgress = FALSE;
  222.     m_request = request;
  223.     m_requestindex = 0;
  224. }        
  225.  
  226. int CHTTPSocket::ProcessHeader(int size)
  227. {
  228.     if (!m_bInHeader) 
  229.     {
  230. //        AddLog("vege a headernek, mit keresek itt");
  231.         return 0;
  232.     }
  233.  
  234.     int i = 0;
  235.     BOOL eob = FALSE;
  236.     CString current = m_sBlockRemain;
  237.     m_sBlockRemain.Empty();
  238.  
  239.     while (i < size)
  240.     {
  241.         eob = TRUE;
  242.         while (i < size && eob)
  243.         {
  244.             unsigned char ch = (unsigned char)(m_buf.GetAt(i));
  245.             switch (ch)
  246.             {
  247.             case '\r': 
  248.                 break;
  249.             case '\n': 
  250.                 eob = FALSE;
  251.                 break;
  252.             default:
  253.                 current += ch;
  254.             }
  255.             i++;
  256.         }
  257. //        if (!m_bInHeader)
  258. //        {
  259. //            AddLog("valami baj van ...");
  260. //        }
  261. //        AddLog("|" + current + "|");
  262.         if (current.IsEmpty())
  263.         {
  264.             m_bInHeader = FALSE;
  265. //            AddLog("---------------------------------");
  266.             return i;
  267.         }
  268.         else
  269.         if (!eob)
  270.         {
  271.             int colon = current.Find(':');
  272.             if (m_bFirstLine)
  273.             {
  274.                 m_bFirstLine = FALSE;
  275.  
  276.                 int space = current.Find(' ');
  277.                 if (space != -1)
  278.                 {
  279.                     current = current.Mid(space + 1);
  280.                     space = current.Find(' ');
  281.                     if (space != -1)
  282.                     {
  283.                         current = current.Left(space);
  284.                     }
  285.                     m_iCode = atoi((LPCSTR) current);
  286.                     if (m_iCode != 200)
  287.                     {
  288.                         if (m_iCode >= 300 || m_iCode <= 302)
  289.                         {
  290.                             m_bRedirect = TRUE;
  291.                         }
  292.                         else
  293.                         {
  294.                             m_bError = TRUE;
  295.                         }
  296.                     }
  297.                 }
  298.             }
  299.             else
  300.             if (colon != -1)
  301.             {
  302.                 CString name = current.Left(colon);
  303.                 CString value = current.Mid(colon + 1);
  304.                 name.MakeLower();
  305.                 value.TrimLeft();
  306.                 if (!name.Compare("content-length"))
  307.                 {
  308.                     if (m_progress)
  309.                     {
  310.                         m_progress -> SetRange(0, atoi((LPCSTR) value));
  311.                         m_bProgress = TRUE;
  312.                     }
  313.                 }
  314.                 else
  315.                 if (!name.Compare("location"))
  316.                 {
  317.                     location = value;
  318.                 }
  319.                 else
  320.                 if (!name.Compare("content-type"))
  321.                 {
  322.                     m_bDocument = !value.Compare("text/html");
  323.                 }
  324.                 m_Header.SetAt(name, value);
  325. //                AfxMessageBox(name + ":" + value, MB_APPLMODAL | MB_OK);
  326.             }
  327.             current.Empty();
  328.         }
  329.     }
  330.     m_sBlockRemain = current;
  331. //    AddLog("............");
  332.     return (size + 1);
  333. }
  334.  
  335. void CHTTPSocket::StatusRead(int size)
  336. {
  337.     if (m_bProgress)
  338.     {
  339.         m_progress -> OffsetPos(size);
  340.     }
  341.     *m_numBytes += size;
  342. }
  343.  
  344. int CHTTPSocket::OutputData(BYTE * odata, int len)
  345. {
  346.     if (m_bError)
  347.     {
  348.         return 1;
  349.     }
  350.     if (m_bRedirect) 
  351.     {
  352.         return 1;
  353.     }
  354.     if (!m_bFileInited)
  355.     {
  356.         m_bFileInited = TRUE;
  357.         if (!initfile())
  358.         {
  359.             m_bError = TRUE;
  360.             return 1;
  361.         }
  362.     }
  363.     StatusRead(len);
  364.     if (m_bDocument)
  365.     {
  366.         int i = htmltemp.GetSize();
  367.  
  368.         //parse HTML file
  369.         htmltemp.SetSize(i + len);
  370.         BYTE *data = htmltemp.GetData();
  371.         BYTE *data2 = data;
  372.         memcpy(data + i, odata, len);
  373.         len += i;
  374.         
  375.         BYTE *s1 = data, *end = data + len, *s2,
  376.              *start = data, *tagend;
  377.  
  378.         while (s1 < end)
  379.         {
  380.             if (*s1 == '<')
  381.             {
  382.                 start = s1++;
  383.                 
  384.                 int intag = 1, quot = 0; // 1 = ", 2 = '
  385.                 while (s1 < end && intag)
  386.                 {
  387.                     if (*s1 == '>' && quot == 0)
  388.                     {
  389.                         intag = 0;
  390.                         break;
  391.                     }
  392.                     else
  393.                     if (*s1 == '\"')
  394.                     {
  395.                         if (quot == 0)
  396.                         {
  397.                             quot = 1;
  398.                         }
  399.                         else
  400.                         if (quot == 1)
  401.                         {
  402.                             quot = 0;
  403.                         }
  404.                     }
  405.                     else
  406.                     if (*s1 == '\'')
  407.                     {
  408.                         if (quot == 0)
  409.                         {
  410.                             quot = 2;
  411.                         }
  412.                         else
  413.                         if (quot == 2)
  414.                         {
  415.                             quot = 0;
  416.                         }
  417.                     }
  418.                     s1++;
  419.                 }
  420.                 if (!intag)
  421.                 {
  422.                     tagend = s1;
  423.                     CString tagname, tagparam, tagvalue;
  424.  
  425.                     s1 = start + 1;
  426.  
  427. #define NEXTCHAR            while (s1 < tagend && (*s1 == ' ' || *s1 == '\t' || *s1 == '\n' || *s1 == '\r')) s1++
  428. #define NOTBLANKCHAR(s1)    (*s1 != ' ' && *s1 != '\t' && *s1 != '\n' && *s1 != '\r')
  429.  
  430.                     NEXTCHAR;
  431.                     if (s1 < tagend)
  432.                     {
  433.                         while (s1 < tagend && NOTBLANKCHAR(s1))
  434.                         {
  435.                             tagname += *(s1 ++);
  436.                         }
  437.                     }
  438.                     tagname.MakeLower();
  439.                     if (!tagname.Compare("!--"))
  440.                     {
  441.                         start = tagend + 1;
  442.                         continue;
  443.                     }
  444.                     start = tagend + 1;
  445.                     while (s1 < tagend)
  446.                     {
  447.                         tagparam.Empty();
  448.                         tagvalue.Empty();
  449.  
  450.                         NEXTCHAR;
  451.                         while (s1 < tagend && NOTBLANKCHAR(s1) && *s1 != '=')
  452.                         {
  453.                             tagparam += *(s1 ++);
  454.                         }
  455.                         tagparam.MakeLower();
  456.                         if (s1 < tagend && *s1 == '=')
  457.                         {
  458.                             s2 = ++s1;
  459.                             NEXTCHAR;
  460.                             if (s1 < tagend)
  461.                             {
  462.                                 char delim = ' ';
  463.  
  464.                                 if (*s1 == '\"') 
  465.                                 {
  466.                                     delim = '\"';
  467.                                     s1++;
  468.                                 }
  469.                                 else
  470.                                 if (*s1 == '\'')
  471.                                 {
  472.                                     delim = '\'';
  473.                                     s1++;
  474.                                 }
  475.                                 while (s1 < tagend)
  476.                                 {
  477.                                     if (delim == ' ' && (*s1 == ' ' || *s1 == '\t' || 
  478.                                                          *s1 == '\r' || *s1 == '\n' ||
  479.                                                          *s1 == '\'' || *s1 == '\"'))
  480.                                     {
  481.                                         break;
  482.                                     }
  483.                                     else
  484.                                     if (delim == *s1)
  485.                                     {
  486.                                         s1++;
  487.                                         break;
  488.                                     }
  489.                                     else
  490.                                     {
  491.                                         tagvalue += *s1;
  492.                                         s1++;
  493.                                     }
  494.                                 }
  495.                                 unescape(tagvalue);
  496.                                 if (!tagname.Compare("base") && !tagparam.Compare("href"))
  497.                                 {
  498.                                     base = tagvalue;
  499.                                 }
  500.                                 else
  501.                                 if (tagLink(tagname, tagparam))
  502.                                 {
  503.                                     CString exp = expandedURL(tagvalue, base);
  504.                                     int hash = exp.Find('#');
  505.                                     if (hash != -1)
  506.                                     {
  507.                                         exp = exp.Left(hash);
  508.                                     }
  509.                                     int x1, x2 = exp.GetLength();
  510.                                     CString exp2;
  511.  
  512.                                     for (x1 = 0; x1 < x2; x1++)
  513.                                     {
  514.                                         char c = exp[x1];
  515.                                         if (c != '\r' && c != '\n')
  516.                                             exp2 += c;
  517.                                     }
  518.                                     exp = exp2;
  519.  
  520.                                     if (!links -> Find(exp))
  521.                                     {
  522.                                         CURL exptemp(exp);
  523.  
  524.                                         if (!exptemp.scheme.Compare("http"))
  525.                                         {
  526.                                             if (exptemp.path.IsEmpty())
  527.                                             {
  528.                                                 exptemp.path = "/";
  529.                                                 exptemp.build(exp);
  530.                                             }
  531.                                             exptemp.fragment.Empty();
  532.                                             switch (session -> m_Mirror)
  533.                                             {
  534.                                             case 0: if (islocal(exp))
  535.                                                     {
  536.                                                         if (!inserverlist(exptemp.net_loc, session -> m_Exclude))
  537.                                                         {
  538.                                                             links -> AddTail(exp);
  539.                                                             AddLog("ADD", exp);
  540.                                                         }
  541.                                                         if (session -> m_LocalURLs)
  542.                                                         {
  543.                                                             int i = s2 - data;
  544.                                                             m_File.Write(data, i);
  545.                                                             len -= i;
  546.                                                             data = s2;
  547.  
  548.                                                             i = s1 - s2;
  549.                                                             len -= i;
  550.                                                             data = s1;
  551.                                                             CString temp = makelocal(exp, base);
  552.                                                             if (delim != ' ')
  553.                                                             {
  554.                                                                 temp = delim + temp + delim;
  555.                                                             }
  556.                                                             m_File.Write((LPCSTR)temp, temp.GetLength());
  557.                                                         }
  558.                                                     }
  559.                                                     break;
  560.                                             case 1: if (!inserverlist(exptemp.net_loc, session -> m_Exclude) &&
  561.                                                         exptemp.net_loc == session -> url.net_loc) 
  562.                                                     {
  563.                                                         links -> AddTail(exp);
  564.                                                         AddLog("ADD", exp);
  565.                                                     }
  566.                                                     break;
  567.                                             case 2: if (!inserverlist(exptemp.net_loc, session -> m_Exclude) &&
  568.                                                         domain(exptemp.net_loc) == domain(session -> url.net_loc))
  569.                                                     {
  570.                                                         links -> AddTail(exp);
  571.                                                         AddLog("ADD", exp);
  572.                                                     }
  573.                                                     break;
  574.                                             case 3:    if (!inserverlist(exptemp.net_loc, session -> m_Exclude))
  575.                                                     {
  576.                                                         links -> AddTail(exp);
  577.                                                         AddLog("ADD", exp);
  578.                                                     }
  579.                                                     break;
  580.                                             }
  581.                                         }
  582.                                     }
  583.                                 }
  584.                             }
  585.                         }
  586.                     }
  587.                 }
  588.             }
  589.             else
  590.             {
  591.                 s1++;
  592.             }
  593.         }
  594.  
  595.         i = end - start;
  596.         m_File.Write(data, len - i);
  597.         memcpy(data2, start, i);
  598.         htmltemp.SetSize(i);
  599.     }
  600.     else
  601.     {
  602.         m_File.Write(odata, len);
  603.     }
  604.     return 1;
  605. }
  606.  
  607. BOOL CHTTPSocket::tagLink(CString name, CString param)
  608. {
  609.   return (name == "a"        && param == "href") ||
  610.          (name == "area"    && param == "href") ||
  611.          (name == "img"        && param == "src") ||
  612.          (name == "body"    && param == "background") ||
  613.          (name == "script"    && param == "src") ||
  614.          (name == "frame"    && param == "src") ||
  615.          (name == "layer"    && param == "src") ||
  616.          (name == "embed"    && param == "src") ||
  617.          (name == "link"    && param == "src");
  618. }
  619.  
  620. CString CHTTPSocket::expandedURL(CString rel, CString base)
  621. {
  622.     CString expanded(base);
  623.     CURL urel(rel);
  624.     CURL ubase(base);
  625.  
  626.     CURL *uexpanded = urel.expand(&ubase);
  627.     uexpanded -> build(expanded);
  628.     delete uexpanded;
  629.     return expanded;
  630. }
  631.  
  632.  
  633. CString CHTTPSocket::getfilename(CString url)
  634. {
  635.     CURL uurl(url);
  636.     CURL ubase(session -> m_BaseURL);
  637.     
  638.     if (session -> m_FullName || uurl.net_loc.Compare(ubase.net_loc) != 0)
  639.     {
  640.         CString temp = uurl.path;
  641.         return convertname((uurl.net_loc) + temp);
  642.     }
  643.     
  644.     CString purl = getpath(uurl.path);
  645.     CString pbase = getpath(ubase.path);
  646.     CString purlstart = purl.Left(pbase.GetLength());
  647.     
  648.     CString res;
  649.  
  650.     if (!pbase.Compare(purlstart))
  651.     {
  652.         res = convertname(purl.Mid(pbase.GetLength()) + getname(uurl.path));
  653.     }
  654.     else
  655.     {
  656.         res = convertname(purl);
  657.     }
  658.     if (session -> m_LongFileName == 1)
  659.     {
  660.         res = convert83(res);
  661.     }
  662.     else
  663.     if (session -> m_LongFileName == 2)
  664.     {
  665.         res = convert83c(res);
  666.     }
  667.     return res;
  668. }
  669.  
  670. CString CHTTPSocket::getpath(CString str)
  671. {
  672.     CString result;
  673.  
  674.     int i = str.GetLength() - 1;
  675.     while (i > 0 && str[i] != '/' && str[i] != '\\') i--;
  676.     if (i)
  677.     {
  678.         result = str.Left(i + 1);
  679.     }
  680.  
  681.     if (result.IsEmpty())
  682.     {
  683.         result = "/";
  684.     }
  685.     return result;
  686. }
  687.  
  688. CString CHTTPSocket::getname(CString str)
  689. {
  690.     CString result;
  691.  
  692.     int i = str.GetLength() - 1;
  693.     while (i > 0 && str[i] != '/' && str[i] != '\\') i--;
  694.     if (i)
  695.     {
  696.         result = str.Mid(i + 1);
  697.     }
  698.     else
  699.     {
  700.         result = str;
  701.     }
  702.     if (result.IsEmpty())
  703.     {
  704.         return "index.html";
  705.     }
  706.     else
  707.     {
  708.         return result;
  709.     }
  710. }
  711.  
  712. int CHTTPSocket::gethex(char c)
  713. {
  714.     if (c >= '0' && c <= '9')
  715.     {
  716.         return c - '0';
  717.     }
  718.     else
  719.     if (c >= 'a' && c <= 'f')
  720.     {
  721.         return c - 'a' + 10;
  722.     }
  723.     else
  724.     if (c >= 'A' && c <= 'F')
  725.     {
  726.         return c - 'A' + 10;
  727.     }
  728.     else
  729.     {
  730.         return 0;
  731.     }
  732. }
  733.  
  734. CString CHTTPSocket::convertname(CString str)
  735. {
  736.     for (int i = 0; i < str.GetLength(); i++)
  737.     {
  738.         if (str[i] == '%')
  739.         {
  740.             char c1, c2;
  741.             if (i < str.GetLength() - 2)
  742.             {
  743.                 c1 = str[i + 1];
  744.             }
  745.             else
  746.             {
  747.                 c1 = 0;
  748.             }
  749.             if (i < str.GetLength() - 3)
  750.             {
  751.                 c2 = str[i + 2]; 
  752.             }
  753.             else 
  754.             {
  755.                 c2 = 0;
  756.             }
  757.             strDelete(str, i, 2);
  758.             c1 = (gethex(c1) << 4) + gethex(c2);
  759.             if (c1 == '/' || c1 == '\\') 
  760.             {
  761.                 c1 = '_';
  762.             }
  763.             str.SetAt(i, c1);
  764.         }
  765.     }
  766.     if (str[str.GetLength() - 1] == '/')
  767.     {
  768.         str += "index.html";
  769.     }
  770.     if (str[0] == '/')
  771.     {
  772.         str = str.Mid(1);
  773.     }
  774.     for (i = 0; i < str.GetLength(); i++)
  775.     {
  776.         if (str[i] == '/') 
  777.         {
  778.             str.SetAt(i, '\\'); 
  779.         }
  780.         else
  781.         if (strchr("<>:\"|?*", str[i]) || str[i] < 32) 
  782.         {
  783.             str.SetAt(i, '_');
  784.         }
  785.     }
  786.  
  787.     return str;
  788. }
  789.  
  790. CString CHTTPSocket::strDelete(CString& str, int start, int count)
  791. {
  792.     str = str.Left(start) + str.Mid(start + count);
  793.     return str;
  794. }
  795.  
  796. CString CHTTPSocket::convert83frag(CString str)
  797. {
  798.     CString ext, name;
  799.     if (str[0] == '.')
  800.     {
  801.         str = str.Mid(1);  //dos alatt nem lehet pont a kezdokarakter
  802.     }
  803.     for (int i = str.GetLength() - 1; i >= 0 && str[i] != '.'; i--);
  804.     if (i >= 0)
  805.     {
  806.         ext = shorten(str.Mid(i + 1), 3);
  807.         name = shorten(str.Left(i), 8);
  808.     }
  809.     else //nincs kiterjesztes
  810.     {
  811.         name = shorten(str, 8);
  812.     }
  813.     if (ext.IsEmpty())
  814.     {
  815.         return name;
  816.     }
  817.     else
  818.     {
  819.         return name + "." + ext;
  820.     }
  821. }
  822.  
  823. CString CHTTPSocket::convert83(CString str)
  824. {
  825.     CString temp, result;
  826.     for (int i = 0; i < str.GetLength(); i++)
  827.     {
  828.         if (str[i] == '/' || str[i] == '\\')
  829.         {
  830.             result += convert83frag(temp) + "/";
  831.             temp.Empty();
  832.         }
  833.         else
  834.         {
  835.             temp += str[i];
  836.         }
  837.     }
  838.     return result + convert83frag(temp);
  839. }
  840.  
  841. CString CHTTPSocket::shorten(CString str, int max)
  842. {
  843.     for (int i = 0; i < str.GetLength(); i++)
  844.     {
  845.         if (strchr("+,;=[]. ", str[i])) 
  846.         {
  847.             str.SetAt(i, '_');
  848.         }
  849.     }
  850.  
  851.     while (str.GetLength() > max)
  852.     {
  853.         i = str.Find('_');
  854.         if (i < 0)
  855.         {
  856.             break;
  857.         }
  858.         else
  859.         {
  860.             strDelete(str, i, 1);
  861.         }
  862.     }
  863.     for (i = str.GetLength() - 1; i >= 0 && str[i] >= '0' && str[i] <= '9'; i--);
  864.     while (str.GetLength() > max)
  865.     {
  866.         strDelete(str, i--, 1);
  867.         if (i < 0)
  868.         {
  869.             i = 0;
  870.         }
  871.     }
  872.     return str;
  873. }
  874.  
  875. CString CHTTPSocket::makelocal(CString url, CString sbase)
  876. {
  877.     CString purl = getpath(url);
  878.     CString pbase = getpath(sbase);
  879.     CString local, diff;
  880.     for (int i = 0; i < purl.GetLength() && i < pbase.GetLength() && purl[i] == pbase[i]; i++);
  881.     diff = pbase.Mid(i);
  882.     url = url.Mid(i);
  883.     for (int j = 0; j < diff.GetLength(); j++)
  884.     {
  885.         if (diff[j] == '/')
  886.         {
  887.             local += "../";
  888.         }
  889.     }
  890.     return local + url;
  891. }
  892.  
  893. int CHTTPSocket::initfile()
  894. {
  895.     for (int i = 0; i < m_filename.GetLength(); i++)
  896.     {
  897.         if (m_filename[i] == '/') 
  898.         {
  899.             m_filename.SetAt(i, '\\');
  900.         }
  901.     }
  902.     CString directory = m_filename.Left(m_filename.ReverseFind('\\'));
  903.     if (directory.IsEmpty())
  904.     {
  905.         directory = "C:\\";
  906.     }
  907.     else
  908.     if (directory[directory.GetLength() - 1] != '\\')
  909.     {
  910.         directory += '\\';
  911.     }
  912.     if (!CreateDirectoryTree(directory))
  913.     {
  914.         return 0;
  915.     }
  916.     else
  917.     {
  918.         return m_File.Open(m_filename, CFile :: modeCreate | CFile :: modeWrite | CFile::shareDenyWrite);
  919.     }
  920. }
  921.  
  922. int CHTTPSocket::islocal(CString url)
  923. {
  924.     CURL uurl(url);
  925.     CString purl = getpath(uurl.path);
  926.     CString pbase = getpath(session -> url.path);
  927.     CString temp = purl.Left(pbase.GetLength());
  928.     return uurl.net_loc == basenet_loc &&
  929.            temp == pbase;
  930. }
  931.  
  932. CString CHTTPSocket::shortenc(CString str, int max)
  933. {
  934.     for (int i = 0; i < str.GetLength(); i++)
  935.     {
  936.         if (strchr("+,;=[]. ", str[i])) 
  937.         {
  938.             str.SetAt(i,'_');
  939.         }
  940.     }
  941.  
  942.     if (str.GetLength() <= max)
  943.     {
  944.         return str;
  945.     }
  946.         
  947.     unsigned long l = crc32(0, (const unsigned char *)(LPCSTR) str, str.GetLength());
  948.     char buf[9];
  949.     sprintf(buf, "%08lx", l);
  950.     return buf;
  951. }
  952.  
  953. CString CHTTPSocket::convert83fragc(CString str)
  954. {
  955.     CString ext, name;
  956.     if (str[0] == '.')
  957.     {
  958.         str = str.Mid(1);  //dos alatt nem lehet pont a kezdokarakter
  959.     }
  960.     for (int i = str.GetLength() - 1; i >= 0 && str[i] != '.'; i--);
  961.     if (i >= 0)
  962.     {
  963.         ext = shorten(str.Mid(i + 1), 3);
  964.         name = shortenc(str.Left(i), 8);
  965.     }
  966.     else //nincs kiterjesztes
  967.     {
  968.         name = shortenc(str, 8);
  969.     }
  970.     if (ext.IsEmpty())
  971.     {
  972.         return name;
  973.     }
  974.     else
  975.     {
  976.         return name + "." + ext;
  977.     }
  978. }
  979.  
  980. CString CHTTPSocket::convert83c(CString str)
  981. {
  982.     CString temp, result;
  983.     for (int i = 0; i < str.GetLength(); i++)
  984.     {
  985.         if (str[i] == '/' || str[i] == '\\')
  986.         {
  987.             result += convert83fragc(temp) + "/";
  988.             temp.Empty();
  989.         }
  990.         else
  991.         {
  992.             temp += str[i];
  993.         }
  994.     }
  995.     return result + convert83fragc(temp);
  996. }
  997.  
  998. CTime CHTTPSocket::RFC1123(CString str)
  999. {
  1000.     CString wkday[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  1001.     CString mon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1002.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  1003.     char sday[4], smonth[4];
  1004.     int year, month, day, hour, min, sec;
  1005.     
  1006.     if (sscanf((LPCSTR)str, "%3s, %2d %3s %4d %2d:%2d:%2d GMT",
  1007.         sday, &day, smonth, &year, &hour, &min, &sec) != 7) 
  1008.     {
  1009.         return CTime :: GetCurrentTime();
  1010.     }
  1011.     for (int i = 0; i < 7; i++)
  1012.     {
  1013.         if (!wkday[i].Compare(sday)) 
  1014.         {
  1015.             break;
  1016.         }
  1017.     }
  1018.     if (i >= 7) 
  1019.     {
  1020.         return CTime :: GetCurrentTime();
  1021.     }
  1022.     
  1023.     for (i = 0; i < 12; i++)
  1024.     {
  1025.         if (!mon[i].Compare(smonth)) 
  1026.         {
  1027.             break;
  1028.         }
  1029.     }
  1030.     if (i >= 12) 
  1031.     {
  1032.         return CTime :: GetCurrentTime();
  1033.     }
  1034.     month = i + 1;
  1035.     CTime temp(year, month, day, hour, min, sec);
  1036.     return ValidTime(temp);
  1037. }
  1038.  
  1039. CTime CHTTPSocket::RFC850(CString str)
  1040. {
  1041.     CString weekday[7] = {"Sunday,", "Monday,", "Tuesday,", "Wednesday,", "Thursday,",
  1042.         "Friday,", "Saturday,"};
  1043.     CString mon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1044.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  1045.  
  1046.     char sday[12], smonth[4];
  1047.     int year, month, day, hour, min, sec;
  1048.     
  1049.     if (sscanf((LPCSTR)str, "%s %2d-%3s-%2d %2d:%2d:%2d GMT",
  1050.         sday, &day, smonth, &year, &hour, &min, &sec) != 7) 
  1051.     {
  1052.         return CTime :: GetCurrentTime();
  1053.     }
  1054.  
  1055.     for (int i = 0; i < 7; i++)
  1056.     {
  1057.         if (!weekday[i].Compare(sday)) 
  1058.         {
  1059.             break;
  1060.         }
  1061.     }
  1062.     if (i >= 7) 
  1063.     {
  1064.         return CTime :: GetCurrentTime();
  1065.     }
  1066.     
  1067.     for (i = 0; i < 12; i++)
  1068.     {
  1069.         if (!mon[i].Compare(smonth)) 
  1070.         {
  1071.             break;
  1072.         }
  1073.     }
  1074.     if (i >= 12) 
  1075.     {
  1076.         return CTime :: GetCurrentTime();
  1077.     }
  1078.     month = i + 1;
  1079.     
  1080.     if (year < 70)
  1081.     {
  1082.         year += 2000;
  1083.     }
  1084.     else
  1085.     {
  1086.         year += 1900;
  1087.     }
  1088.     
  1089.     CTime temp(year, month, day, hour, min, sec);
  1090.     return ValidTime(temp);
  1091. }
  1092.  
  1093. CTime CHTTPSocket::asc(CString str)
  1094. {
  1095.     CString wkday[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  1096.     CString mon[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1097.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  1098.     char sday[4], smonth[4];
  1099.     int year, month, day, hour, min, sec;
  1100.     
  1101.     if (sscanf((LPCSTR)str, "%3s %3s %2d %02d:%02d:%02d %4d",
  1102.         sday, smonth, &day, &hour, &min, &sec, &year) != 7) 
  1103.     {
  1104.         return CTime :: GetCurrentTime();
  1105.     }
  1106.     for (int i = 0; i < 7; i++)
  1107.     {
  1108.         if (!wkday[i].Compare(sday)) 
  1109.         {
  1110.             break;
  1111.         }
  1112.     }
  1113.     if (i >= 7) 
  1114.     {
  1115.         return CTime :: GetCurrentTime();
  1116.     }
  1117.     
  1118.     for (i = 0; i < 12; i++)
  1119.     {
  1120.         if (!mon[i].Compare(smonth)) 
  1121.         {
  1122.             break;
  1123.         }
  1124.     }
  1125.     if (i >= 12) 
  1126.     {
  1127.         return CTime :: GetCurrentTime();
  1128.     }
  1129.     month = i + 1;
  1130.     CTime temp(year, month, day, hour, min, sec);
  1131.     return ValidTime(temp);
  1132. }
  1133.  
  1134. CTime CHTTPSocket::ValidTime(CTime time)
  1135. {
  1136.     if (time.GetYear() >= 1980 && 
  1137.         time.GetMonth() >= 1 && time.GetMonth() <= 12 && 
  1138.         time.GetDay() >= 1 && time.GetDay() <= 31 &&
  1139.         time.GetHour() >= 0 && time.GetHour() < 24 && 
  1140.         time.GetMinute() >= 0 && time.GetMinute() < 60 && 
  1141.         time.GetSecond() >= 0 && time.GetSecond() < 60) 
  1142.     {
  1143.         return time;
  1144.     }
  1145.     else
  1146.     {
  1147.         return CTime :: GetCurrentTime();
  1148.     }
  1149. }
  1150.  
  1151. CString CHTTPSocket::FormatTime(CTime time)
  1152. {
  1153.     return time.Format("%a, %d %b %Y %H:%M:%S GMT");
  1154. }
  1155.  
  1156. BOOL CHTTPSocket::inserverlist(CString server, CString list)
  1157. {
  1158.     CString temp;
  1159.  
  1160.     int i = 0;
  1161.     while (i < list.GetLength())
  1162.     {
  1163.         if (list[i] == ';')
  1164.         {
  1165.             temp.TrimLeft();
  1166.             temp.TrimRight();
  1167.             if (regularCompare(server, temp))
  1168.             {
  1169.                 return TRUE;
  1170.             }
  1171.             temp = "";
  1172.         }
  1173.         else
  1174.         {
  1175.             temp += list[i];
  1176.         }
  1177.         i++;
  1178.     }
  1179.     temp.TrimLeft();
  1180.     temp.TrimRight();
  1181.     return regularCompare(server, temp);
  1182. }
  1183.  
  1184. BOOL CHTTPSocket::regularCompare(LPCSTR str, LPCSTR mask)
  1185. {
  1186.     while (*str && *mask)
  1187.     {
  1188.         if (*mask == '?')
  1189.         {
  1190.             str++;
  1191.             mask++;
  1192.         }
  1193.         else
  1194.         if (*mask == '*')
  1195.         {
  1196.             int b = 0;
  1197.                 
  1198.             while (*mask == '*') mask++;
  1199.             while (*str && !b)
  1200.             {
  1201.                 str++;
  1202.                 if (regularCompare(str, mask)) 
  1203.                 {
  1204.                     b = 1;
  1205.                 }
  1206.             }
  1207.             if (!b)
  1208.             {
  1209.                 break;
  1210.             }
  1211.         }
  1212.         else
  1213.         if (*str == *mask)
  1214.         {
  1215.             str++;
  1216.             mask++;
  1217.         }
  1218.         else
  1219.         {
  1220.             return 0;
  1221.         }
  1222.     }
  1223.     return *str == *mask;
  1224. }
  1225.  
  1226. CString CHTTPSocket::mimeencode(CString str)
  1227. {
  1228.     const char table[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"};
  1229.     
  1230.     unsigned char c1, c2, c3, e1, e2, e3, e4;
  1231.     int i = 0, c = str.GetLength();
  1232.     CString res;
  1233.     
  1234.     while (i < c)
  1235.     {
  1236.         c1 = str[i];
  1237.         if (i + 1 < c) 
  1238.         {
  1239.             c2 = str[i + 1]; 
  1240.         }
  1241.         else 
  1242.         {
  1243.             c2 = 0;
  1244.         }
  1245.         if (i + 2 < c) 
  1246.         {
  1247.             c3 = str[i + 2]; 
  1248.         }
  1249.         else 
  1250.         {
  1251.             c3 = 0;
  1252.         }
  1253.         
  1254.         e1 = c1 >> 2;      //111111 112222 222233 333333
  1255.         e2 = ((c1 & 0x03) << 4) + (c2 >> 4);
  1256.         e3 = ((c2 & 0x0f) << 2) + (c3 >> 6);
  1257.         e4 = c3 & 0x3f;
  1258.         
  1259.         res = res + table[e1] + table[e2];
  1260.         if (i + 1 < c) 
  1261.         {
  1262.             res += table[e3]; 
  1263.         }
  1264.         else 
  1265.         {
  1266.             res += '=';
  1267.         }
  1268.         if (i + 2 < c) 
  1269.         {
  1270.             res += table[e4]; 
  1271.         }
  1272.         else 
  1273.         {
  1274.             res += '=';
  1275.         }
  1276.         i += 3;
  1277.     }
  1278.     return res;
  1279. }
  1280.  
  1281. void CHTTPSocket::AddDump(CString str)
  1282. {
  1283.     str += "\r\n";
  1284. //    ((CMirrorItApp *)AfxGetApp()) -> theDumpFile.Write((LPCSTR)str, str.GetLength());
  1285. }
  1286.  
  1287. void CHTTPSocket::AddLog(CString type, CString str)
  1288. {
  1289.     CString temp;
  1290.     int i = str.GetLength(), j = 0;
  1291.  
  1292.     while (j < i)
  1293.     {
  1294.         switch(str[j])
  1295.         {
  1296.         case '\r': break;
  1297.         case '\n': temp += "\n";
  1298.                    if (j < i - 1)
  1299.                        temp = type + "-" + temp;
  1300.                    else
  1301.                        temp = type + " " + temp;
  1302.                    ((CMirrorItApp *)AfxGetApp()) -> theLogFile.WriteString(temp);
  1303.                    temp.Empty();
  1304.                    break;
  1305.         default:   temp += str[j];
  1306.                    break;
  1307.         }
  1308.         j++;
  1309.     }
  1310.     if (temp.IsEmpty()) return;
  1311.     temp = type + " " + temp + "\n";
  1312.     ((CMirrorItApp *)AfxGetApp()) -> theLogFile.WriteString(temp);
  1313. }
  1314.  
  1315. int CreateDirectoryTree(CString dir)
  1316. {
  1317.     int UNC = dir.GetLength() > 2 && dir[0] == '\\' && dir[1] == '\\';
  1318.     int j;
  1319.  
  1320.     CString temp;
  1321.     if (UNC)
  1322.     {
  1323.         for (j = 2; j < dir.GetLength() && dir[j] != '\\'; j++);
  1324.         temp = dir.Left(++j);
  1325.     }
  1326.     else
  1327.     {
  1328.         temp = dir.Left(3);
  1329.         j = 3;
  1330.     }
  1331.  
  1332.     for (int i = j; i < dir.GetLength(); i++)
  1333.     {
  1334.         if (dir[i] == '\\')
  1335.         {
  1336.             int j = CreateDirectory2(temp);
  1337.             if (!j) return 0;
  1338.             temp += '\\';
  1339.         }
  1340.         else
  1341.         {
  1342.             temp += dir[i];
  1343.         }
  1344.     }
  1345.     if (!temp.IsEmpty() && temp[temp.GetLength() - 1] != '\\')
  1346.     {
  1347.         return CreateDirectory2(temp);
  1348.     }
  1349.     else
  1350.     {
  1351.         return 1;
  1352.     }
  1353. }
  1354.  
  1355. int CreateDirectory2(CString dir)
  1356. {
  1357.     WIN32_FIND_DATA fd;
  1358.     HANDLE fh = FindFirstFile((LPCSTR)dir, &fd);
  1359.     if (fh == INVALID_HANDLE_VALUE)
  1360.     {
  1361.         return CreateDirectory((LPCSTR)dir, NULL);
  1362.     }
  1363.     FindClose(fh);
  1364.     return 1;
  1365. }
  1366.  
  1367. CString CHTTPSocket::domain(CString str)
  1368. {
  1369.     int i = str.ReverseFind('.');
  1370.     if (i == -1) return str;
  1371.     
  1372.     CString last = str.Mid(i);
  1373.     str = str.Left(i);
  1374.  
  1375.     i = str.ReverseFind('.');
  1376.     if (i != -1) str = str.Mid(i + 1);
  1377.     return str + last;
  1378. }
  1379.  
  1380. void CHTTPSocket::unescape(CString & str)
  1381. {
  1382.     ReplaceStr(str, "&", "%26");
  1383. }
  1384.  
  1385. void CHTTPSocket::ReplaceStr(CString & str, CString from, CString to)
  1386. {
  1387.     int i;
  1388.  
  1389.     while ((i = str.Find(from)) != -1)
  1390.     {
  1391.         str = str.Left(i) + to + str.Mid(i + from.GetLength());
  1392.     }
  1393. }
  1394.