
/******************************************************************************
 *   Copyright 1998-2006 NetBurner   ALL RIGHTS RESERVED
 *
 *   Permission is hereby granted to purchasers of NetBurner hardware to use or
 *   modify this computer program for any use as long as the resultant program
 *   is only executed on NetBurner provided hardware.
 *
 *   No other rights to use this program or its derivatives in part or in whole
 *   are granted.
 *
 *   It may be possible to license this or other NetBurner software for use on
 *   non-NetBurner hardware. Please contact licensing@netburner.com for more
 *   infomation.
 *
 *   NetBurner makes no representation or warranties with respect to the
 *   performance of this computer program, and specifically disclaims any
 *   responsibility for any damages, special or consequential, connected with
 *   the use of this program.
 *
 * ----------------------------------------------------------------------------
 *
 *   NetBurner, Inc.
 *   5405 Morehouse Drive, Suite 200
 *   San Diego, CA  92121
 *
 *   Information available at:  http://www.netburner.com
 *   E-mail:                    info@netburner.com
 *
 *   Support is available:      support@netburner.com
 ******************************************************************************/

#include "predef.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "includes.h"
#include "cfinter.h"
#include "utils.h"
#include "counters.h"
#include "constants.h"
#include "ip.h"
#include "arp.h"
#include "iosys.h"
#include "tcp.h"
#include "http.h"
#include "htmlfiles.h"


#define ESCAPE_STATE_NORMAL         ( 0 )
#define ESCAPE_STATE_LASTWAS_ZERO   ( 1 )
#define ESCAPE_STATE_FIRST_FUNC     ( 2 )
#define ESCAPE_STATE_SECOND_FUNC    ( 3 )


int DoHtmlFunction( int sock, PCSTR url, WORD func_num );
void DoHtmlVariable( int sock,WORD var_num );


void SendHTMLHeader( int sock );
void SendXMLHeader( int sock );
void SendTextHeader( int sock );
void SendGifHeader( int sock );
void SendHeader( int sock, const char *mime_txt );
int BaseInterfaceOK( int sock, HTML_FILE_RECORD * rec );
void ForbiddenResponse( int sock, PCSTR url );


////////////////////////////////////////////////////////////////////////////////
// compf
//
static int compf( const void *p1, const void *p2 )
{
   const char *t1 = ( const char * ) p1;
   const char *t2 = ( ( const HTML_FILE_RECORD * ) p2 )->fname;
   int d = stricmp( t1, t2 );
   return d;
}


////////////////////////////////////////////////////////////////////////////////
// GetRecordFromName
//
HTML_FILE_RECORD *GetRecordFromName( char *name )
{
   if ( ( n_file_record == 1 ) && ( stricmp( name, file_record[0].fname ) == 0 ) )
   {
      return ( HTML_FILE_RECORD * ) file_record;
   }

   return ( HTML_FILE_RECORD * ) bsearch( name,
                                          file_record,
                                          n_file_record,
                                          sizeof( HTML_FILE_RECORD ),
                                          compf );
}


////////////////////////////////////////////////////////////////////////////////
// SendCompressed
//
void SendCompressed( int sock, char *pData, int siz )
{
   writeall( sock, pData, siz );
}


////////////////////////////////////////////////////////////////////////////////
// SendHtml
//
void SendHtml( int sock, char *pData, int siz, PCSTR url )
{
   PoolPtr pp = GetBuffer();
   pp->usedsize = 0;
   unsigned char *cp = ( unsigned char * ) pData;

   while ( 1 )
   {
      if ( *cp == 255 )
      {
         break;
      }

      if ( *cp == 0 )
      {
         cp++;

         if ( *cp == 1 )
         {
            //
            // HTML fill-in function
            //
            cp++;
            WORD fnum = ( *cp++ ) << 8;
            fnum |= *cp++;

            if ( pp->usedsize )
            {
               writeall( sock, ( char * ) pp->pData, pp->usedsize );
            }

            pp->usedsize = 0;
            DoHtmlFunction( sock, url, fnum );
         }
		 else
		 if(*cp==2)
		  {
			 cp++;
			 WORD fnum = ( *cp++ ) << 8;
			 fnum |= *cp++;

			 if ( pp->usedsize )
			 {
				writeall( sock, ( char * ) pp->pData, pp->usedsize );
			 }

			 pp->usedsize = 0;
 		     DoHtmlVariable(sock,fnum);
		  }
         else
         {
            pp->pData[pp->usedsize++] = *( cp++ );
         }
      }
      else if ( *cp >= 128 )
      {
         //
         // HTML code word
         //
         pp->pData[pp->usedsize++] = '<';
         const char *cpw;

         if ( *cp >= ( 128 + 64 ) )
         {
            pp->pData[pp->usedsize++] = '/';
            cpw = html_table[( *cp ) - ( 128 + 64 )];
         }
         else
         {
            cpw = html_table[( *cp ) - 128];
         }

         while ( *cpw )
         {
            pp->pData[pp->usedsize++] = *( cpw++ );
         }

         cp++;
      }
      else
      {
         //
         // Normal char
         //
         pp->pData[pp->usedsize++] = *( cp++ );
      }

      if ( pp->usedsize > 512 )
      {
         writeall( sock, ( char * ) pp->pData, pp->usedsize );
         pp->usedsize = 0;
      }
   }

   if ( pp->usedsize )
   {
      writeall( sock, ( char * ) pp->pData, pp->usedsize );
   }

   FreeBuffer( pp );
}


////////////////////////////////////////////////////////////////////////////////
// SendData
//
void SendData( HTML_FILE_RECORD *fr, int sock, PCSTR url )
{
   switch ( fr->cType )
   {
      case eNoCompression:
         writeall( sock, ( char * ) fr->file_pointer, fr->siz );
         break;
      case eHuffman:
         SendCompressed( sock, ( char * ) fr->file_pointer, fr->siz );
         break;
      case eHuffmanHtml:
      case eUncompHtml:
         if ( fr->has_calls )
         {
             SendHtml( sock, ( char * ) fr->file_pointer, fr->siz, url );
         }
         else
         {
             // We write (size - 1) bytes, because the Html format has stuck an
             // extra byte (0xFF) at the end of the filerecord. This way we can
             // avoid transmitting that byte.
             writeall( sock, ( char * ) fr->file_pointer, fr->siz - 1 );
         }
         break;
   }
}



void SendXMLHeader( int sock )
{
   writestring( sock,
                "HTTP/1.0 200 OK\r\nPragma: no-cache\r\nContent-Type: text/xml\r\n\r\n" );
}



////////////////////////////////////////////////////////////////////////////////
// SendHeader
//
void SendHeader( int sock, const char *mime_txt, int len )
{
   char buffer[255];
   if ( len )
   {
       siprintf( buffer,
                 "HTTP/1.0 200 OK\r\nPragma: no-cache\r\nMIME-version: 1.0\r\nContent-Type: %s\r\nContent-length: %d\r\n\r\n",
                 mime_txt,
                 len );
   }
   else
   {
       siprintf( buffer,
                 "HTTP/1.0 200 OK\r\nPragma: no-cache\r\nMIME-version: 1.0\r\nContent-Type: %s\r\n\r\n",
                 mime_txt );
   }
   writestring( sock, buffer );
}


////////////////////////////////////////////////////////////////////////////////
// SendFullResponse
//
int SendFullResponse( char *name, int sock )
{
   char *search = name;
   char old_val;

   while ( ( *search ) && ( *search != '?' ) )
   {
      search++;
   }

   old_val = *search;
   *search = 0;
   HTML_FILE_RECORD *fr = GetRecordFromName( name );
   *search = old_val;

   if ( fr == NULL )
   {
      return 0;
   }

   if (!BaseInterfaceOK( sock, fr )) {
        ForbiddenResponse( sock, name);
        return 1;
   }
   // if the file record's type index is -1, it doesn't exist in
   // the MIME table so send it as text/plain
   int contentLength = 0;
   if (!fr->has_calls) {
       if (fr->cType == eUncompHtml)    { contentLength = fr->siz - 1; }
       else                             { contentLength = fr->siz; }
   }
   SendHeader( sock,
       ( fr->fType >= 0 ) ? MIME_table[fr->fType] : "text/plain",
       contentLength );

   DBPRINT( DB_HTTP, "Decoding " );
   DBPRINT( DB_HTTP, name );
   DBPRINT( DB_HTTP, "\r\n" );

   SendData( fr, sock, name );
   return 1;
}


////////////////////////////////////////////////////////////////////////////////
// SendHeaderResponse
//
int SendHeaderResponse( char *name, int sock )
{
   char *search = name;
   char old_val;

   while ( ( *search ) && ( *search != '?' ) )
   {
      search++;
   }

   old_val = *search;
   *search = 0;
   HTML_FILE_RECORD *fr = GetRecordFromName( name );
   *search = old_val;

   if ( fr == NULL )
   {
      return 0;
   }

   if (!BaseInterfaceOK( sock, fr )) {
        ForbiddenResponse( sock, name);
        return 1;
   }
   // if
   // if the file record's type index is -1, it doesn't exist in
   // the MIME table so send it as text/plain
   int contentLength = 0;
   if (!fr->has_calls) {
       if (fr->cType == eUncompHtml)    { contentLength = fr->siz - 1; }
       else                             { contentLength = fr->siz; }
   }

   SendHeader( sock,
       ( fr->fType >= 0 ) ? MIME_table[fr->fType] : "text/plain"
       , contentLength);
   return 1;
}


////////////////////////////////////////////////////////////////////////////////
// SendFileFragment
//
int SendFileFragment( char *name, int sock, PCSTR url )
{
   HTML_FILE_RECORD *fr = GetRecordFromName( name );

   if ( fr == NULL )
   {
      return 0;
   }

   if (!BaseInterfaceOK( sock, fr )) {
        ForbiddenResponse( sock, name);
        return 1;
   }
   SendData( fr, sock,url );
   return 1;
}
