#define XVT_INCL_NATIVE
#include <xvt.h>
#include <progind.h>
#include <config.h>
#include <agasys.h>
#include <utility.h>

// skstream.h
// Copyright (C) 1995, 1996 by John C. Wang. All Rights Reserved.
//
// You may distribute this file with your product in either of two ways:
// IN SOURCE CODE FORM: You must include this file in its entirety.
// IN OBJECT CODE FORM: You must give proper acknowledgements to the author(s)
//   of this program. This may take the form of credits on the start-up screen.
//
// IN ANYCASE, THIS SOFTWARE IS DISTRIBUTED WITHOUT ANY KIND OF EXPLICIT OR
// IMPLICIT WARRANTIES AND THE AUTHORS ARE NOT RESPONSIBLE FOR ANY EVENTS THAT
// OCCURS AS A RESULT OF USING THIS SOFTWARE.
//
// History:
// [JCW 95-Dec-04] created
// [JCW 95-Dec-20] comments added for distribution 95a
// [JCW 96-Jan-01] removed UDP capabilities from skstream

#ifdef INCSTR_H
#include <incstr.h>
#endif

#ifdef WIN32
#include "winsock.h"
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#define SOCKET int
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define SOCKADDR_IN sockaddr_in
#define closesocket close
#define BYTE byte
#endif

//
// sockbuf
//
class sockbuf : public streambuf
{
public:
  sockbuf( SOCKET & );
  sockbuf( SOCKET &, char *, int );

  virtual ~sockbuf();

  virtual int overflow(int =EOF) ;
  virtual int underflow() ;

    virtual int sync();

protected:
  char *_buffer ;

  // sockbuf specific
  SOCKET &_socket ;
} ;


//
// skstream
//
class skstream : public iostream {
public:
  // constants
  enum service
  {
    ftp         =      21, //tcp
    telnet      =      23, //tcp
    smtp        =      25, //tcp       mail
    time        =      37, //tcp       timserver
    name        =      42, //tcp       nameserver
    nameserver  =      53, //tcp       domain        # name-domain server
    finger      =      79, //tcp
    http        =      80, //tcp
    pop         =     109, //tcp       postoffice
    pop2        =     109, //tcp                     # Post Office
    pop3        =     110, //tcp       postoffice
    nntp        =     119  //tcp       usenet        # Network News Transfer
  } ;

  enum role
  {
    server ,
    client
  } ;

  // methods
  skstream( void );
  skstream( const char *addr, const service, const role = client ) ;
  skstream( SOCKET );
  ~skstream( void );

  void open( const char *addr, const service, const role = client ) ;
  void close( void ) ;
  int is_open( void ) const ;
  void attach( SOCKET = NULL );
  SOCKET getsocket() const ;

  char *getpeername( char *, int ) const ;
  unsigned short getport( void ) const ;
protected:
  SOCKET _socket ;
  sockbuf _sockbuf ;

  // platform dependent library housekeeping
  int init( void ) ;
  int shutdown( void ) ;
};

// skstream.cpp
// Copyright (C) 1996, 1995 by John C. Wang <jcwang@csie.ntu.edu.tw>
// All Rights Reserved.
//
// You may distribute this file with your product in either of two ways:
// IN SOURCE CODE FORM: You must include this file in its entirety.
// IN OBJECT CODE FORM: You must give proper acknowledgements to the author(s)
//   of this program. This may take the form of credits on the start-up screen.
//
// IN ANYCASE, THIS SOFTWARE IS DISTRIBUTED WITHOUT ANY KIND OF EXPLICIT OR
// IMPLICIT WARRANTY AND THE AUTHOR(S) ARE NOT RESPONSIBLE FOR ANY EVENT THAT
// OCCURS DUE TO THE USE OR MISUSE OF THIS SOFTWARE.
//
// History:
// [JCW 95-Dec-04] created.
// [JCW 95-Dec-20] comments added for distribution 95a.
// [JCW 96-Jan-01] removed UDP capabilities from skstream.
// [JCW 96-Mar-14] exceptions made optional.
// [JCW 96-Oct-20] protected skstream::init and ::shutdown changed.
//                 char( 255 ) == EOF bug fixed.

#ifdef _UNIX
#define INVALID_SOCKET -1
// Add definitions here
#endif

// Machine independent macros
#ifdef DBG
  #define dassert(x) assert(x)
  #define debug(x) x
#else
  #define dassert(x)
  #define debug(x)
#endif //def _DEBUG

//
// skstream
//

int skstream::init( void )
{
  // platform dependent initialization
#ifdef WIN32
  const WORD wMinVer = 0x0101;  // request WinSock v1.1 (at least)
  WSADATA wsaData;
  if( 0 == WSAStartup( wMinVer, &wsaData ) )
    return TRUE ;
  return FALSE ;
#else
	return TRUE;
#endif
}

int skstream::shutdown( void )
{
  // platform dependent shutdown
#ifdef WIN32
  if( 0 == WSACleanup() )
    return TRUE ;
  return FALSE ;
#else
	return TRUE;
#endif
}

skstream::skstream( void ) : iostream( &_sockbuf ), _sockbuf( _socket )
{
  if( init() )
    attach( INVALID_SOCKET ) ;
}

skstream::skstream( const char *addr, const service port, const role side )
 : iostream( &_sockbuf ), _sockbuf( _socket )
{
  if( init() )
  {
    attach( INVALID_SOCKET ) ;
    open( addr, port, side ) ;
  }
}

skstream::skstream( SOCKET sock ) : iostream( &_sockbuf ), _sockbuf( _socket )
{
  if( init() )
    attach( sock ) ;
}

skstream::~skstream( void )
{
  close() ;
  shutdown() ;
}

int skstream::is_open( void ) const
{
  return ( INVALID_SOCKET != getsocket() ) ;
}

void skstream::open( const char *addr, const service port, const role side )
{
  // in case of error condition, user finds out by testing is_open()

  if( is_open() )
    close() ;
  
  // 1. Create socket
  if( INVALID_SOCKET == ( _socket = ::socket( PF_INET, SOCK_STREAM, 0 ) ) )
    // Cannot create socket
    return ;

  // 2. Bind
  SOCKADDR_IN sa ;
  sa.sin_family = AF_INET ;
#ifdef WIN32
  sa.sin_addr.S_un.S_addr = INADDR_ANY ;
#else  
  sa.sin_addr.s_addr = INADDR_ANY ;
#endif  
  sa.sin_port = side == client ? 0 : htons( (unsigned short)port ) ;
    // rationale: no client requires fixed port number, so let system assign
  if( SOCKET_ERROR == ::bind( _socket, (sockaddr *)&sa, sizeof( sa ) ) )
  {
    // Cannot bind to the chosen port
    close() ;
    return ;
  }

  // From now on the two sides are very much different
  if( side == skstream::client )
  {
    // 3(cli). Connect
    SOCKADDR_IN sa ; memset(&sa,0,sizeof(sa));
    sa.sin_family = AF_INET ;
                               
    unsigned long indirizzo = 0xFFFFFFFF;
    
    int ip[4];
//e' un indirizzo numerico?
//si...    
    if (sscanf( addr, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]) == 4)
    {
      indirizzo = ::inet_addr(addr);
    }
//no...
    else
    { 
      hostent* he = ::gethostbyname( addr );    
      if( NULL != he )
        indirizzo = *(unsigned long *)( he->h_addr_list[ 0 ] );
    }
    
    if (indirizzo == 0 || indirizzo == 0xFFFFFFFF)
    {
      close();
      return;
    }
    
#ifdef WIN32
    sa.sin_addr.S_un.S_addr = indirizzo;
    sa.sin_port = ::htons( port ) ;
#else
    sa.sin_addr.s_addr = indirizzo;
    sa.sin_port = htons( port ) ;
#endif

    if( SOCKET_ERROR == ::connect( _socket, (sockaddr *)&sa, sizeof( sa ) ) )
    {
      // Connection error
      close() ;
      return ;
    }
  }
  else
  {
    // 3(svr). Listen
    if( SOCKET_ERROR == ::listen( _socket, 5 ) )  // max backlog
    {
      // Error listening
      close() ;
      return ;
    }

    // 4. Accept
    SOCKET commsock ;
    if( INVALID_SOCKET == ( commsock = ::accept( _socket, NULL, NULL ) ) )
    {
      // Accepting error
      close() ;
      return ;
    }

    // rationale: after we accept a connection, close the server port
    //   so another process may become a server
    if( SOCKET_ERROR == ::closesocket( _socket ) )
    {
      // Cannot close service port, resource may be occupied
      close() ;
      return ;
    }
    _socket = commsock ;
  }
  // success!
}

void skstream::close( void )
{
  if( is_open() )
  {
    _sockbuf.sync() ;
    if( SOCKET_ERROR == ::closesocket( _socket ) )
      // Cannot close. Leave _socket as it was
      return ;
  }

  _socket = INVALID_SOCKET ;
}

void skstream::attach( SOCKET sock )
{
  _socket = sock ;
}

SOCKET skstream::getsocket() const
{
  return _socket ;
}

char *skstream::getpeername( char *buf, int size ) const
{
  SOCKADDR_IN sa ;
  int sasize = sizeof( sa ) ;
#ifdef WIN32
  if( SOCKET_ERROR ==::getpeername( getsocket(), (sockaddr *)&sa, &sasize ) )
#else
  if( SOCKET_ERROR ==::getpeername( getsocket(), (sockaddr *)&sa, (socklen_t *) &sasize ) )
#endif
    // Cannot get peer name
    return NULL ;
  strncpy( buf, ::inet_ntoa( sa.sin_addr ), size - 1 ) ;
  return buf ;
}

unsigned short skstream::getport( void ) const
{
  SOCKADDR_IN sa ;
  int sasize = sizeof( sa ) ;
#ifdef WIN32
  if( SOCKET_ERROR ==::getpeername( getsocket(), (sockaddr *)&sa, &sasize ) )
    // Cannot get peer port
    return ::ntohs( IPPORT_RESERVED ); 
  return ::ntohs( sa.sin_port ) ;
#else
  if( SOCKET_ERROR ==::getpeername( getsocket(), (sockaddr *)&sa, (socklen_t *) &sasize ) )
    // Cannot get peer port
    return ntohs( IPPORT_RESERVED ); 
  return ntohs( sa.sin_port ) ;
#endif
}

//
//  sockbuf
//
sockbuf::sockbuf( SOCKET &sock ) : _socket( sock ) 
{
  const int insize = 0x2000 ;   // allocate 16k buffer each for input and output
  const int outsize = 0x2000 ;
  const int bufsize = insize + outsize ;

  _buffer = new char [ bufsize ] ;

  if( this != setbuf( _buffer, bufsize ) )
    _buffer = NULL ;
  else
  {
    setp( _buffer, _buffer + insize ) ;
    setg( _buffer + insize, _buffer + bufsize, _buffer + bufsize ) ;
  }
}

sockbuf::sockbuf( SOCKET &sock, char *buf, int length ) : _socket( sock )
{
  _buffer = NULL ;

  if( this == setbuf( buf, length ) )
	{
  	setp( buf, buf + length / 2 ) ;
  	setg( buf + length / 2, buf + length, buf + length ) ;
  }
}

sockbuf::~sockbuf()
{
  delete[] _buffer ;
  _buffer = NULL ;
}

int sockbuf::overflow( int nCh )
{
  // in case of error, user finds out by testing fail()
  if( _socket == INVALID_SOCKET )
    // Invalid socket
    return EOF ;

  if( pptr() - pbase() <= 0 )
    // nothing to send
    return 0 ;

  int size ;
  if( SOCKET_ERROR == ( size = ::send( _socket, pbase(), pptr() - pbase(), 0 ) ) )
    // (TCP) Cannot send
    return EOF ;

  if( size == 0 )
    // remote site has closed this connection
    return EOF ;

  if( nCh != EOF )  // size >= 1 at this point
  {
    size-- ;
    *( pbase() + size ) = nCh ;
  }

  // move remaining pbase() + size .. pptr() - 1 => pbase() .. pptr() - size - 1
  for( char *p = pbase() + size; p < pptr(); p++ )
    *( p - size ) = *p ;
  const int newlen = ( pptr() - pbase() ) - size ;

  setp( pbase(), epptr() ) ;
  pbump( newlen ) ;

  return 0 ;
}

int sockbuf::underflow()
{
  // if get area not empty, return first character
  // else fill up get area and return 1st character

  // in case of error, user finds out by testing eof()

  if( _socket == INVALID_SOCKET )
    // Invalid socket!
    return EOF ;

  if( egptr() - gptr() > 0 )
    return (int)(unsigned char)(*gptr()) ;

  // fill up from eback to egptr
  int size ;
  if( SOCKET_ERROR == ( size = ::recv( _socket, eback(), egptr() - eback(), 0 ) ) )
    // (TCP) Receive error
    return EOF ;

  if( size == 0 )
    // remote site has closed this connection
    return EOF ;

  // move rcvd data from eback() .. eback() + size to egptr() - size .. egptr()
  const int delta = egptr() - ( eback() + size ) ;
  for( char *p = eback() + size - 1; p >= eback(); p-- )
  {
    CHECK( p + delta >= eback(), "Socket underflow" ) ;
    CHECK( p + delta < egptr(), "Socket underflow" ) ;
    *( p + delta ) = *p ;
  }

  setg( eback(), egptr() - size, egptr() ) ;

  return (int)(unsigned char)(*gptr()) ;
}

int sockbuf::sync()
{
  if( EOF == overflow() )
    return EOF ;  // ios will set the fail bit
  else
  {
    // empty put and get areas
    setp( pbase(), epptr() ) ;
    setg( eback(), egptr(), egptr() ) ;
    
    return 0 ;
  }
}

///////////////////////////////////////////////////////////
// end of skstreams
///////////////////////////////////////////////////////////

#include "netsock.h"

class TSocket_connection : public TConnection
{
	TString _server;
  skstream::service _service;

  skstream* _socket;

protected:
  bool connect();
 
public:
  virtual bool Execute(const char* cmd);

  bool WriteLine(const char* cmd);
  bool ReadLine(TString& str);
  bool Read(byte* buf, size_t size);

  skstream* GetSocket();

	TSocket_connection(TLanManager* lm, const char* service, const char* server);
	~TSocket_connection();
};

bool TSocket_connection::Execute(const char* cmd)
{
	skstream* calza = GetSocket();
	bool ok = calza != NULL;
  if (ok)
	{
    const size_t buflen = strlen(cmd)+1;
    calza->sync();
    calza->write(cmd, buflen);
    calza->flush();
    ok = calza->good() != 0;
	}
	return ok;
}

bool TSocket_connection::WriteLine(const char* cmd)
{
	skstream* calza = GetSocket();
	bool ok = calza != NULL;
  if (ok)
	{
    const size_t buflen = strlen(cmd); // Unica differenza da Execute
    calza->sync();
    calza->write(cmd, buflen);
    calza->flush();
    ok = calza->good() != 0;
	}
	return ok;
}

bool TSocket_connection::ReadLine(TString& str)
{
	skstream* calza = GetSocket();
	bool ok = calza != NULL;
	if (ok)
	{
    char *buf = str.get_buffer(4096);
    calza->getline(buf, str.size(), '\n');
	}
	return ok;
}

bool TSocket_connection::Read(byte* buf, size_t size)
{
	skstream* calza = GetSocket();
	bool ok = calza != NULL;
	if (ok)
	{
    calza->read((char *)buf, size);
		ok = calza->good() != 0;
	}
	return ok;
}

bool TSocket_connection::connect()
{ 
	if (_socket != NULL)
		delete _socket;
  _socket = new skstream(_server, _service);
	if (_socket->is_open())
	  SetId((CONNID)_socket);
  else
  {
    delete _socket;
    _socket = NULL;
	  SetId(0);
  }  

	return _socket != NULL;
}

skstream* TSocket_connection::GetSocket()
{
	if (_socket == NULL || !_socket->is_open())
		connect();
	return _socket;
}

TSocket_connection::TSocket_connection(TLanManager* lm, 
																			 const char* service, const char* server) 
                  : TConnection(lm, 0), _socket(NULL)
{
  _service = (skstream::service)((service && *service) ? atoi(service) : 0);

  _server = server;
  int pos = _server.find("://");
  if (pos > 0)
    _server.ltrim(pos+3);

  pos = _server.rfind(':');
  if (pos >= 0)
  {
    _service = (skstream::service)atoi(_server.mid(pos+1));
    _server.cut(pos);
  }

  if (_server.blank() || xvt_str_compare_ignoring_case(_server, "localhost") == 0)
    _server = "127.0.0.1";           

	connect();
}

TSocket_connection::~TSocket_connection()
{
	if (_socket)
		delete _socket;
}

TSocketClient::TSocketClient() 
      : m_pData(NULL), m_dwSize(0)
{ }

TSocketClient::~TSocketClient()
{ 
  ReleaseBuffer();
  RemoveAllConnections();
}

TConnection* TSocketClient::OnQueryConnection(const char* service, const char* server)
{
  TSocket_connection* pConnection = new TSocket_connection(this, service, server);
	if (pConnection->Id() == 0)
	{
		delete pConnection;
		pConnection = NULL;
	}


  return pConnection;
}

bool TSocketClient::Request(CONNID id, const char* cmd)
{   
  static bool semaphore = FALSE;
  bool ok = FALSE;

  if (!semaphore)
  {
    semaphore = TRUE;
    
    ReleaseBuffer();
    ok = Execute(id, cmd);
    if (ok)
    {                                  
			TSocket_connection* conn = (TSocket_connection*)GetConnection(id);
      m_dwSize = 0;
      conn->Read((byte*)&m_dwSize, sizeof(m_dwSize));
      ok = m_dwSize > 0;
      if (ok)
      {
        m_pData = new byte[m_dwSize];
        ok = conn->Read(m_pData, m_dwSize);
      }
    }

    semaphore = FALSE;
  }
  return ok;
}

byte* TSocketClient::GetBuffer(size_t& dwSize)
{
  dwSize = m_dwSize;
  return m_pData;
}

bool TSocketClient::WriteLine(CONNID id, const char* str)
{
	TSocket_connection* conn = (TSocket_connection*)GetConnection(id);
	if (conn)
    return conn->WriteLine(str);
  return FALSE;
}


bool TSocketClient::ReadLine(CONNID id, TString& str)
{
	TSocket_connection* conn = (TSocket_connection*)GetConnection(id);
	if (conn)
    return conn->ReadLine(str);
	return FALSE;
}

void TSocketClient::ReleaseBuffer()
{
  if (m_pData)
  {
    delete m_pData;
    m_pData = NULL;
    m_dwSize = 0;
  }
}

bool TSocketClient::HttpGetFile(CONNID id, const char* remote, const char* local, const char* authorization)

{
  bool ok = FALSE;
   
  TString buf(4096);
  buf << "GET " << remote << " HTTP/1.0\r\n"
      << "User-Agent: Campo\r\n";
  if (authorization && *authorization)
    buf << "Authorization: " << authorization << "\r\n";
  buf << "\r\n";

  if (WriteLine(id, buf))


  {
    long size = 0;
    for (int r = 0; ; r++)
    {
			ReadLine(id, buf);
      if (buf.blank())
        break;
      if (r == 0 && buf.find("200 OK") < 0)
        return FALSE;    // File not found
      if (buf.compare("Content-length:", 15, TRUE) == 0)
      {
        const int colon = buf.find(':');
        size = atol(buf.mid(colon+1));
      }
    }
    ofstream outfile(local, ios::out | ios::binary);
    if (outfile.good())
    {    
      buf.cut(0) << remote << " - " << (size / 1024 + 1) << " KBytes"; 
      TProgind pi(size, buf, TRUE, TRUE);

      long total = 0;
       
      skstream* cur_socket = ((TSocket_connection*)GetConnection(id))->GetSocket();
      while (!cur_socket->eof())
      {
        cur_socket->read(buf.get_buffer(), buf.size());
        const int count = cur_socket->gcount();
        if (count > 0)
        {
          outfile.write(buf, count);  
          total += count;
          pi.setstatus(total);
          if (pi.iscancelled())
            break;
        }
      }
      ok = pi.isfinished();
    } 
    else 
      error_box("Impossibile scrivere il file %s", local);
  }
  return ok;
}

HIDDEN int find_href(const TString& riga)
{
  int href = -1;
  int img = riga.find("<img");
  if (img >= 0)
    href = riga.find("href=", img+4);
  else
  {
    img = riga.find("<IMG");
    if (img >= 0)
      href = riga.find("HREF=", img+4);
  }
  return href;
}
 
bool TSocketClient::HttpGetDir(CONNID id, const char* remote, TString_array& list)
{
  TFilename local; local.temp();
  const bool ok = HttpGetFile(id, remote, local);
  if (ok)
  {
    ifstream s(local);
    TString riga(256);
    while (!s.eof())
    {
      s.getline(riga.get_buffer(), riga.size());
      const int href = find_href(riga);
      if (href > 0)
      {
        const int start = riga.find('"', href) + 1;
        if (start > href && isalnum(riga[start + 1]))
        {
          const int stop  = riga.find('"', start);
          if (stop > start)
          {
            const TString& name = riga.sub(start, stop);
            list.add(name);
          }
        }
      }
    }
    s.close();
    ::remove(local);
  }

  return ok;
}

bool TSocketClient::HttpSoap(CONNID id, const char* cmd)
{
  bool ok = false;

	TSocket_connection* conn = (TSocket_connection*)GetConnection(id);
  if (conn == NULL)
    return ok;
  
  if (cmd == NULL || *cmd == '\0')
    return ok;

	char hostname[256];
  xvt_sys_get_host_name(hostname, sizeof(hostname));

	TString content(256);
	content = cmd;
	if (content.find("<SOAP-ENV") < 0)  // Controllo se c'� tutto
	{
	  content.insert("<SOAP-ENV:Envelope>\n<SOAP-ENV:Body>\n");
		content << "</SOAP-ENV:Body>\n</SOAP-ENV:Envelope>\r\n";
	}

  TString buf(4096);
	buf << "POST / HTTP/1.1\n"
		  << "User-Agent: Campo\n"
	    << "Host: " << hostname << "\n"
		  << "Content-Type: text/xml; charset=utf-8\n"
		  << "Content-length: " << content.len() << "\n"
	    << "SOAPAction: \"/\"\r\n\r\n"
			<< content;

  if (conn->WriteLine(buf))
  {
		skstream* cur_socket = conn->GetSocket();

    unsigned long size = 0;
    for (int r = 0; !cur_socket->eof(); r++)
    {
			conn->ReadLine(buf);
      if (buf.blank())
        break;
      if (buf.compare("Content-length:", 15, TRUE) == 0)
      {
        const int colon = buf.find(':');
        size = atol(buf.mid(colon+1));
      }
    }
    if (size > 0)
		{
			if (size >= m_dwSize)
			{
			  ReleaseBuffer();
			  m_dwSize = size+1;
        m_pData = new BYTE[m_dwSize];
			}
			memset(m_pData, 0, m_dwSize);
			cur_socket->read((char *) m_pData, size);
			ok = true;
		}
	}
  return ok;
} 

bool TSocketClient::HttpPostFile(CONNID id, const char* remote, const char* local, const char* authorization)
{
  bool ok = false;

	TSocket_connection* conn = (TSocket_connection*)GetConnection(id);
  if (conn == NULL)
    return ok;
  const char* const eol = "\r\n";

  TString buf(4096);
  buf << "POST " << remote << " HTTP/1.0" << eol
      << "User-Agent: Campo/1.7" << eol
      << "Content-Type: text/plain" << eol
      << "Content-Length: " << fsize(local) << eol;
  if (authorization && *authorization)
    buf << "Authorization: " << authorization << eol;
  buf << eol;
  
  ok = conn->WriteLine(buf); 
  if (ok)
  {
#ifdef WIN32
    ifstream input(local, ios::nocreate | ios::binary);
#else
    ifstream input(local, ios::binary);
#endif
    while (!input.eof())
    {
      input.read(buf.get_buffer(), buf.size());
      const size_t count = input.gcount();
      if (count > 0)
      {
				skstream* cur_socket = conn->GetSocket();

        cur_socket->sync();
        cur_socket->write(buf, count);
        cur_socket->flush();
      }
      else
        break;
    }
    conn->ReadLine(buf);
    ok = buf.find("200 OK") >= 0;
                    
    if (ok)                
    {
			skstream* cur_socket = conn->GetSocket();
      unsigned long size = 0;
      for (int r = 0; !cur_socket->eof(); r++)
      {
        cur_socket->getline(buf.get_buffer(), buf.size(), '\n');
        if (buf.blank())
          break;
        if (buf.starts_with("Content-length:", true) == 0)
        {
          const int colon = buf.find(':');
          size = atol(buf.mid(colon+1));
        }
      }
      ReleaseBuffer();
      ok = size > 0;
      if (ok)
      {
        m_dwSize = size;
        m_pData = new BYTE[m_dwSize+1];
        memset(m_pData, 0, size_t(m_dwSize+1));
        cur_socket->read((char *) m_pData, (size_t)m_dwSize);
      }
    }
    else
    {
      ReleaseBuffer();
      m_dwSize = buf.len()+1;
      m_pData = new BYTE[m_dwSize];
      memcpy(m_pData, buf, (size_t)m_dwSize);
    }
  }
  
  return ok;
}