

/* httpserver.cpp   June 2002

   by Dale Heatherington

  This file has the code the http server. It creates
  web pages with server status information. 
  
  As of July 14th 2002 the html generated by this
  module passes the validation test at http://validator.w3.org/

---------------------------------------------------

This program is free software; you can redistribute it and/or modify  
it under the terms of the GNU General Public License as published by      
the Free Software Foundation; either version 2 of the License, or         
(at your option) any later version.                                       
                                                                          
This program is distributed in the hope that it will be useful,       
but WITHOUT ANY WARRANTY; without even the implied warranty of            
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             
GNU General Public License for more details.                              
                                                                          
You should have received a copy of the GNU General Public License     
along with this program; if not, write to the Free Software               
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA                  
                                                                          
---------------------------------------------------

*/

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif


#define _PTHREADS  
  


#include <termios.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>


#include <assert.h>
#include <time.h>
#include <sys/timeb.h>
#include <sys/time.h>

#include <stdio.h>
#include <ctype.h>

#include <sys/stat.h>
#include <fcntl.h>


#include <string.h>
#include <string>

#include <math.h>
#include <stdlib.h>

#include <fstream>
#include <iostream>
#include <strstream>
#include <iomanip>

/*
#ifdef linux
#include <linux/kernel.h>
#include <linux/sys.h>
#endif
*/
#include <sys/resource.h>

//tcpip header files

#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <errno.h>

using namespace std;

#include "dupCheck.h"
#include "cpqueue.h"
#include "utils.h"
#include "constant.h"
#include "history.h"
#include "serialp.h"
#include "aprsString.h"
#include "validate.h"
#include "queryResp.h"
#include "servers.h"


//---------------------------------------------------------------------
#define HTMLSIZE 5000 /* Size of html temp buffer */
#define HSIZE 600     /*Max number of lines the web page may contain. */

int buildMainPage(char** html2send)
{  time_t localtime;
   int  i,idx;
   int fullStreamRate;
   char szTime[64];
   struct tm *gmt = NULL;
   char *htmlbuf = NULL;
   double serverRate = 0;
   double inetRate = 0;
   string inetRateX, serverRateX;
   string xmode ;
   
   idx = 0;

   if(pthread_mutex_lock(pmtxCount) != 0)
        cerr << "Unable to lock pmtxCount - HTTPStats1.\n" << flush;

    webCounter++ ;

    fullStreamRate = getStreamRate(STREAM_FULL);

    if (fullStreamRate > 1000) {
        inetRate = ((double)fullStreamRate / 1000);
        inetRateX = "Kbytes/sec";
        if (inetRate > 1000) {
            inetRate = (inetRate / 1000);
            inetRateX = "Megabytes/sec";
        }
    } else {
        inetRate = (double)fullStreamRate;
        inetRateX = "Bytes/sec";
    }

    if (serverLoad > 1000) {
        serverRate = ((double)serverLoad / 1000);
        serverRateX = "KBytes/sec";
        if (serverRate > 1000) {
            serverRate = (serverRate / 1000);
            serverRateX = "MegaBytes/sec";
        }
    } else {
        serverRate = (double)serverLoad;
        serverRateX = "Bytes/sec";
    }
    

    gmt = new tm;
    time(&localtime);
    gmt = gmtime_r(&localtime,gmt);
    strftime(szTime,64,"%a, %d %b %Y %H:%M:%S GMT",gmt);    // Date in RFC 1123 format
    delete gmt;

    char *szHdumps, *szMicE, *szTrace;

    if(History_ALLOW) szHdumps = "YES";
    else szHdumps = "NO";

    if(ConvertMicE) szMicE = "YES";
    else szMicE = "NO";

    if(traceMode) szTrace = "YES";
    else szTrace = "NO";

    char *stl;

#if STLport
    stl = "-stl";
#else
    stl = "";
#endif


    htmlbuf = new char[HTMLSIZE];
    htmlbuf[HTMLSIZE-1] = '\0';   //Set last byte in buffer to null
    ostrstream stats(htmlbuf,HTMLSIZE-1);
    
 

   stats << setiosflags(ios::showpoint | ios::fixed)
          << setprecision(1)
          << "HTTP/1.0 200 OK\n"
          << "Date: " << szTime << "\n"
          << "Server: aprsd\n"
          << "MIME-version: 1.0\n"
          << "Content-type: text/html\n"
          << "Expires: " << szTime << "\n"
          //<< "Refresh: 300\n"             // uncomment to activate 5 minute refresh time
          << "\n"                           //Blank line terminates headers
          << "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
          << "<HTML>"
          << "<HEAD><TITLE>" << szServerCall << " Server Status Report</TITLE>\n"
          << "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">\n"
          << "<meta name=\"robots\" content=\"noindex,nofollow\"></HEAD>\n"
          << "<BODY LINK=\"#0000FF\" VLINK=\"#800080\" ALINK=\"#FF0000\" BGCOLOR=\"#606060\"><CENTER>"
          << "<P><TABLE BORDER=2 BGCOLOR=\"#D0D0D0\">"
          << "<TR BGCOLOR=\"#FFD700\">"
          << "<TH COLSPAN=2>" << "Server: " << szServerCall << " " << MyLocation 
          << "<BR>" << "Igate: " << MyCall << "</TH>"
          << "</TR>"
          << "<TR ALIGN=center><TD COLSPAN=2>" << szTime << "</TD></TR>\n"
          << "<TR><TD>Server up time</TD><TD>" << upTime << " hours</TD></TR>\n"
          << "<TR><TD>Users</TD><TD>" << getConnectedClients() << "</TD></TR>\n"
          << "<TR><TD>Peak Users</TD><TD>" << MaxConnects << "</TD></TR>\n"
          << "<TR><TD>Max User Limit</TD><TD>" << MaxClients << "</TD></TR>\n"
          << "<TR><TD>Max Server Load (Bps)</TD><TD>" << MaxLoad << "</TD></TR>\n"
          << "<TR><TD>Connect count</TD><TD>" << TotalConnects << "</TD></TR>\n"
          << "<TR><TD>TNC Packets</TD><TD>" << TotalLines << "</TD></TR>\n"
          
          << "<TR><TD>Pkts gated to RF</TD><TD>" << msg_cnt << "</TD></TR>\n"
          << "<TR><TD>Local Count</TD><TD>" << localCount() << "</TD></TR>\n"
          << "<TR><TD>Internet Pkts</TD><TD>" << countIGATED << "</TD></TR>\n"
          << "<TR><TD>NOGATE Pkts</TD><TD>" << countNOGATE <<  "</TD></TR>\n"
          << "<TR><TD>LOOPED Pkts</TD><TD>" << countLOOP <<  "</TD></TR>\n" 
          << "<TR><TD>OVERSIZE Pkts</TD><TD>" << countOVERSIZE <<  "</TD></TR>\n"
          << "<TR><TD>REJECTED Pkts</TD><TD>" << countREJECTED <<  "</TD></TR>\n"
          << "<TR><TD>UDP stream rate</TD><TD>" << getStreamRate(STREAM_UDP) << " Bytes/sec" <<  "</TD></TR>\n"
          << "<TR><TD>Message stream rate</TD><TD>" << getStreamRate(STREAM_MSG) << " Bytes/sec" <<  "</TD></TR>\n"
          << "<TR><TD>TNC stream Rate</TD><TD>" << getStreamRate(STREAM_TNC) << " Bytes/sec</TD></TR>\n"
          << "<TR><TD>User stream rate</TD><TD>" << getStreamRate(STREAM_USER) << " Bytes/sec" <<  "</TD></TR>\n"
          << "<TR><TD>Server/Hub stream rate</TD><TD>" << getStreamRate(STREAM_SERVER) << " Bytes/sec" <<  "</TD></TR>\n"
          << "<TR><TD>Full stream rate -dups</TD><TD>" << inetRate << " " << inetRateX << "</TD></TR>\n"
          << "<TR><TD>Server Load</TD><TD>" << serverRate << " " << serverRateX << "</TD></TR>\n"
          << "<TR><TD>AprsString Objects</TD><TD>" << aprsString::getObjCount() << "</TD></TR>\n"
          << "<TR><TD>History items</TD><TD>" << ItemCount  << "</TD></TR>\n"
          << "<TR><TD>History Time Limit</TD><TD>" << ttlDefault << " min.</TD></TR>\n"
          << "<TR><TD>History dump aborts</TD><TD>" << dumpAborts << "</TD></TR>\n"
          << "<TR><TD>History dumps allowed</TD><TD>" << szHdumps  << "</TD></TR>\n"
          << "<TR><TD>Mic-E conversions </TD><TD>" << szMicE  << "</TD></TR>\n"
          << "<TR><TD>Trace Internet Path </TD><TD>" << szTrace << "</TD></TR>\n"
          << "<TR><TD>Items in InetQ</TD><TD>" << sendQueue.getItemsQueued() << "</TD></TR>\n"
          << "<TR><TD>InetQ overflows</TD><TD>" << sendQueue.overrun << "</TD></TR>\n"
          << "<TR><TD>TncQ overflows</TD><TD>" << tncQueue.overrun << "</TD></TR>\n"
          << "<TR><TD>ConQ overflows</TD><TD>" << conQueue.overrun << "</TD></TR>\n"
          << "<TR><TD>charQ overflows</TD><TD>" << charQueue.overrun << "</TD></TR>\n" 
          << "<TR><TD>HTTP Access Counter</TD><TD>" << webCounter << "</TD></TR>\n"
          << "<TR><TD>?IGATE? Querys</TD><TD>" << queryCounter << "</TD></TR>\n"
          << "<TR><TD>Server Version</TD><TD>" << VERS << stl << "</TD></TR>\n"
          << "<TR><TD>Sysop email</TD><TD><A HREF=\"mailto:" << MyEmail << "\">" << MyEmail << "</A></TD></TR>\n"
          << "</TABLE>"
          << ends;
  
     
  
      if(pthread_mutex_unlock(pmtxCount) != 0)
          cerr << "Unable to unlock pmtxCount - HTTPStats2.\n" << flush;
  
       
      html2send[idx] = new char[strlen(htmlbuf)+1];  //Create space for server status report string
      strcpy(html2send[idx],htmlbuf);                //copy data
      idx++;                                         //increment index 
      
      // Now send the Igate connection report.
  
      char igateheader[] =
  
                 "<P><TABLE BORDER=2 BGCOLOR=\"#C0C0C0\"><TR BGCOLOR=\"#FFD700\">"
                 "<TH COLSPAN=11>Server & Hub Connections</TH></TR>"
                 "<TR><TH>Domain Name</TH><TH>Hex IP<br>Alias</TH><TH>Port</TH><TH>Type</TH><TH>Status</TH><TH>Igate Pgm</TH>"
                 "<TH>Last active<BR>H:M:S</TH><TH>Bytes<BR> In</TH><TH>Bytes<BR> Out</TH><TH>Time<BR> H:M:S</TH><TH>PID</TH></TR>" ;
  
      
      html2send[idx] = new char[strlen(igateheader)+1];
      strcpy(html2send[idx],igateheader);
      idx++;
      
      if(pthread_mutex_lock(pmtxCount) != 0)
          cerr << "Unable to lock pmtxCount - HTTPStats3.\n" << flush;
  
      
      for (i=0; i< nIGATES;i++) {
  
          
  
          if (cpIGATE[i].RemoteSocket != -1) {
              char timeStr[32];
              strElapsedTime(cpIGATE[i].starttime,timeStr);           // Compute elapsed time of connection
              char lastActiveTime[32];
              strElapsedTime(cpIGATE[i].lastActive,lastActiveTime);   // Compute time since last input char
  
  
              ostrstream igateinfo(htmlbuf, HTMLSIZE-1);
              //char *status, *bgcolor, *conType;
              string status, bgcolor, conType;
  
              if (cpIGATE[i].hub) {
                  if (cpIGATE[i].connected) {
                      status = "UP";
                      bgcolor = "\"#C0C0C0\"";
                  } else {
                      status = "N/C" ;
                      bgcolor = "\"#909090\"";
                  }
                  conType = "HUB";
              } else {
                  if (cpIGATE[i].connected) {
                      status = "UP";
                      bgcolor = "\"#C0C0C0\"";
                  } else {
                      status = "DOWN" ;
                      bgcolor = "\"#F07070\"";
                  }
                  conType = "SERVER";
              }

              xmode = "";
              if(cpIGATE[i].mode == MODE_RECV_ONLY) xmode = "-RO";
              if(cpIGATE[i].mode == MODE_RECV_SEND) xmode = "-SR";
  
              string infoTokens[3];
              infoTokens[1] = "*";
              infoTokens[2] = "";
              int ntok = 0;
  
              if (cpIGATE[i].remoteIgateInfo) {
                  string rii(cpIGATE[i].remoteIgateInfo);
  
                  if (rii[0] == '#') {
                      ntok = split(rii, infoTokens, 3, RXwhite);      // Parse into tokens if first char was "#".
                  }                       // Token 1 is remote igate program name and token 2 is the version number.
              }
  
              
              igateinfo << "<TR ALIGN=center BGCOLOR=" << bgcolor << "><TD>"
                  <<  "<A HREF=\"http://"
                  << cpIGATE[i].RemoteName
                  << ":14501/\">" << cpIGATE[i].RemoteName
                  <<  "</A></TD>"
                  << "<TD>" << cpIGATE[i].alias << "</TD>"
                  << "<TD>" << cpIGATE[i].RemoteSocket << "</TD>"
                  << "<TD>" << conType << xmode << "</TD>"
                  << "<TD>" << status << "</TD>"
                  << "<TD>" << infoTokens[1] << " " << infoTokens[2] << "</TD>"
                  << "<TD>" << lastActiveTime << "</TD>"
                  << "<TD>"  << cpIGATE[i].bytesIn / 1024 << " K</TD>"
                  << "<TD>" << cpIGATE[i].bytesOut / 1024 << " K</TD>"
                  << "<TD>" << timeStr << "</TD>"
                  << "<TD>" << cpIGATE[i].pid << "</TD>"
                  << "</TR>\n"
                  << ends; 
             
              
              if(idx < HSIZE){
                  html2send[idx] = new char[strlen(htmlbuf)+1];
                  strcpy(html2send[idx],htmlbuf);
                  idx++;
              }
  
                          
          }
      }
      
      if(pthread_mutex_unlock(pmtxCount) != 0)
          cerr << "Unable to unlock pmtxCount - HTTPStats3.\n" << flush;
  
      char userheader[] =
          "</TABLE><P><TABLE  BORDER=2 BGCOLOR=\"#C0C0C0\">"       // Start of user list table
          "<TR BGCOLOR=\"#FFD700\"><TH COLSPAN=10>Client Connections</TH></TR>\n"
          "<TR><TH>IP Address</TH><TH>Port</TH><TH>Call</TH><TH>Vrfy</TH>"
          "<TH>Program Vers</TH><TH>Last Active<BR>H:M:S</TH><TH>Bytes<BR> In</TH><TH>Bytes <BR>Out</TH><TH>Time<BR> H:M:S</TH><TH>PID</TH></TR>\n" ;
  
      //Copy userheader into the html2send array
      if(idx < HSIZE){
          html2send[idx] = new char[strlen(userheader)+1];
          strcpy(html2send[idx], userheader);
          idx++;
      }
      
      if(pthread_mutex_lock(pmtxAddDelSess) != 0)		// comment this out to allow viewing if mutex is locked
          cerr << "Unable to lock pmtxAddDelSess HTTPStats4- .\n" << flush;
                  
      if(pthread_mutex_lock(pmtxCount) != 0)
          cerr << "Unable to lock pmtxCount - HTTPStats4.\n" << flush;
      
      string TszPeer;
      string TserverPort;
      string TuserCall;
      string TpgmVers;
      string TlastActive;
      string TtimeStr;
      
      int bytesout = 0;
      int bytesin = 0;
      int npid = -1;
  
      


      for (i=0;i<MaxClients;i++) {        // Create html table with user information
  
          
          if ((sessions[i].Socket != -1) 
              && (sessions[i].ServerPort != -1)){

                
              
              char timeStr[32];
              strElapsedTime(sessions[i].starttime, timeStr);      // Compute elapsed time
              char lastActiveTime[32];
              strElapsedTime(sessions[i].lastActive, lastActiveTime);  // Compute elapsed time from last input char
              
              string szVrfy;
              TszPeer = sessions[i].szPeer;
              TuserCall = sessions[i].userCall;
              TpgmVers = sessions[i].pgmVers;
              TlastActive = lastActiveTime;
              TtimeStr = timeStr;
  
              
              removeHTML(TszPeer);
              removeHTML(TuserCall);
              removeHTML(TpgmVers);
              removeHTML(TlastActive);
              removeHTML(TtimeStr);
               
              if (sessions[i].vrfy)
                  szVrfy = "YES";
              else
                  szVrfy = "NO";
  
              if (sessions[i].bytesOut > 0)
                  bytesout = (sessions[i].bytesOut / 1024);
  
              if (sessions[i].bytesIn > 0)
                  bytesin = (sessions[i].bytesIn / 1024);
  
              if (sessions[i].pid > 0)
                  npid = sessions[i].pid;
  
              ostrstream userinfo(htmlbuf,HTMLSIZE-1);
  
              userinfo << "<TR ALIGN=center><TD>"
                       << "<A HREF=\"http://"
                       << TszPeer
                       << ":14501/\">" << TszPeer
                       << "</A></TD>"
                       << "<TD><A target=\"PortInfoFrame\" HREF=\"portinfo." << i << "\">" << sessions[i].ServerPort << "</A></TD>"
                       << "<TD>" << TuserCall  << "</TD>"
                       << "<TD>"  << szVrfy << "</TD>"
                       << "<TD>" << TpgmVers  << "</TD>"
                       << "<TD>" << TlastActive  << "</TD>"
                       << "<TD>" << bytesin << " K</TD>"
                       << "<TD>" << bytesout << " K</TD>"
                       << "<TD>" << TtimeStr  << "</TD>"
                       << "<TD>" << npid << "</TD>"
                       << "</TR>" << endl
                       << ends ;
  
              //Copy each user status line into html2send array
              if(idx < HSIZE){ 
                  html2send[idx] = new char[strlen(htmlbuf)+1];
                  strcpy(html2send[idx],htmlbuf);
                  idx++;
              }
  
                          
          }   //End of if()
  
           
      }   //End of for()
  
     
      
      if(pthread_mutex_unlock(pmtxCount) != 0)
          cerr << "Unable to unlock pmtxCount - HTTPStats4.\n" << flush;
  
      if(pthread_mutex_unlock(pmtxAddDelSess) != 0)
          cerr << "Unable to unlock pmtxAddDelSess - HTTPStats4.\n" << flush;
      
      char endpage[] = "</TABLE></CENTER></BODY></HTML>";
  
      if(idx < HSIZE){
          html2send[idx] = new char[strlen(endpage)+1];
          strcpy(html2send[idx],endpage);
          idx++;
      }

      if(htmlbuf) delete[] htmlbuf; 
      return idx;    //Return number of char buffers used

}

//----------------------------------------------------------------------
unsigned buildPortInfoPage(char** html2send, const string& arg)
{
   time_t localtime;
   unsigned  idx,i;
   char szTime[64];
   struct tm *gmt = NULL;
   char *htmlbuf = NULL;
   long sNum;
   char *endptr;
   gmt = new tm;
   time(&localtime);
   gmt = gmtime_r(&localtime,gmt);
   strftime(szTime,64,"%a, %d %b %Y %H:%M:%S GMT",gmt);    // Date in RFC 1123 format
   delete gmt;

   idx = arg.find_last_of(".");
   if(idx != string::npos){
            string snum = arg.substr(idx+1);  //Get session number in ascii form.
            sNum = strtol(snum.c_str(),&endptr,10);
            if((sNum == 0) && (endptr == snum.c_str())){
               return 0;
            }
            if((sNum >= MaxClients) || (sNum < 0)) return 0;
   }

   if(pthread_mutex_lock(pmtxAddDelSess) != 0)
        cerr << "Unable to lock pmtxAddDelSess - BuildInfoPage\n" << flush;

   
   if ((sessions[sNum].Socket == -1) || (sessions[sNum].ServerPort == -1)) {//No such session?
        if(pthread_mutex_unlock(pmtxAddDelSess) != 0)
               cerr << "Unable to unlock pmtxAddDelSess - BuildInfoPage\n" << flush;
        return 0;
   }

   htmlbuf = new char[HTMLSIZE];
   htmlbuf[HTMLSIZE-1] = '\0';   //Set last byte in buffer to null
   ostrstream stats(htmlbuf,HTMLSIZE-1);

   idx = 0;
   unsigned nBits = sizeof(echomask_t) * 8 ; //Number of bits in the EchoMask

   char emb[nBits + 1];

   for(i=0;i<nBits;i++){
      if(sessions[sNum].EchoMask & (1 << i))
         emb[i] = '1';
      else
         emb[i] = '0';


   }
   emb[i] = '\0';

   char* name[nBits];

   name[0] = "Local TNC";
   name[1] = "User";
   name[2] = "Validated User";
   name[3] = "Server/Hub";
   name[4] = "System Msgs";
   name[5] = "UDP Port";
   name[6] = "History List";
   name[7] = "All Messages";
   name[8] = "Server Stats";
   name[9] = "Server Beacon";
   name[10]= "Rejected Pkts";
   name[11]= "Source Header";
   name[12]= "HTML";
   name[13]= "Raw";
   name[14]= "Duplicates";
   name[15]= "History";
   name[16]= "Echo";
   name[17]= NULL;

   string TszServerCall = szServerCall;
   removeHTML(TszServerCall);
   string TuserCall = sessions[sNum].userCall;
   removeHTML(TuserCall);

   i = 0;
   string emStr = "";
   string color;

   while(name[i]){
      if(emb[i] == '1') color = "<TR BGCOLOR=\"30C030\">";
      else color = "<TR BGCOLOR=\"909090\">";
      emStr = emStr + color + "<TD>" + name[i] + "</TD><TD ALIGN=\"CENTER\" WIDTH=\"20%\">" + emb[i] + "</TD></TR>\n";
      i++;
   }



    
   stats << setiosflags(ios::showpoint | ios::fixed)
         << setprecision(1)                                                                           
         << "HTTP/1.0 200 OK\n"                                                                       
         << "Date: " << szTime << "\n"                                                                
         << "Server: aprsd\n"                                                                         
         << "MIME-version: 1.0\n"                                                                     
         << "Content-type: text/html\n"                                                               
         << "Expires: " << szTime << "\n"                                                             
         << "\n"                           //Blank line terminates headers                            
         << "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"                     
         << "<HTML>"                                                                                  
         << "<HEAD><TITLE>" << TszServerCall << " User Stream Filter Info</TITLE>\n"
         << "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">\n"
         << "<meta name=\"robots\" content=\"noindex,nofollow\"></HEAD>\n"                 
         << "<BODY LINK=\"#0000FF\" VLINK=\"#800080\" ALINK=\"#FF0000\" BGCOLOR=\"#606060\"><CENTER>" 
         << "<P><TABLE WIDTH=\"150\" BORDER=2 BGCOLOR=\"#D0D0D0\">"                                                 
         << "<TR BGCOLOR=\"#FFD700\">"  
         << "<TH COLSPAN=2>Port Filter</TH></TR>\n"
         << "<TR BGCOLOR=\"#FFD700\">"
         << "<TH COLSPAN=2>User: " << TuserCall 
         << "<BR>Port: " << sessions[sNum].ServerPort << "</TH></TR>\n"
         //<< "<TR><TD colspan=2>" << emb << "</TD></TR>"
         << emStr
         << ends ;
         




      if(pthread_mutex_unlock(pmtxAddDelSess) != 0)
               cerr << "Unable to unlock pmtxAddDelSess - BuildPortInfoPage \n" << flush;

      if(idx < HSIZE){ 
         html2send[idx] = new char[strlen(htmlbuf)+1];
         strcpy(html2send[idx],htmlbuf);
         idx++;
      }

           
           char endpage[] = "</TABLE></CENTER></BODY></HTML>";
       
           if(idx < HSIZE){
               html2send[idx] = new char[strlen(endpage)+1];
               strcpy(html2send[idx],endpage);
               idx++;
           }
     
           if(htmlbuf) delete[] htmlbuf; 
           return idx;    //Return number of char buffers used


}

//----------------------------------------------------------------------



/*  Thread to process http request for server status data */

 void *HTTPServerThread(void *p)
{   unsigned idx, i;
    
    char buf[BUFSIZE];
    SessionParams *psp = (SessionParams*)p;
    int sock = psp->Socket;
    delete psp;
    int page_select;
    char  szError[MAX];
    int n, rc,data;
    int err,nTokens; 
       

    if (sock < 0)
        pthread_exit(0);

    
    data = 1;                           // Set socket for non-blocking
    ioctl(sock,FIONBIO,(char*)&data,sizeof(int));

    rc = recvline(sock,buf,BUFSIZE,&err, 10);  //10 sec timeout value

    if (rc<=0) {
        close(sock);
        pthread_exit(0);
    }

    string sLine(buf);
    string token[4];
    nTokens = split(sLine, token, 4, RXwhite);      // Parse http request into tokens

   

    char buf2[127];

    do {
        n = recvline(sock,buf2,126,&err, 1);        // Discard everything else
    } while (n > 0);

    if (n == -2) {
        close(sock);
        pthread_exit(0);
    }

    page_select = 0;
    idx = 0;

    if((token[0].compare("GET") == 0) && (token[1].find("/portinfo.") != string::npos)) {
       page_select = 2;
    }
       
    if ((token[0].compare("GET") == 0) && (token[1].compare("/") == 0)) {
       page_select = 1;
    }

    //Create space for 600 strings to hold the html page
    char **html2send = new char*[HSIZE];    //Hopefully that will be enough!
    for(i=0; i<HSIZE; i++){
        html2send[i] = NULL;                //NULL all the pointers
    }

    /* Assemble page based on value of page_select variable */
    switch(page_select){
    case 1: idx = buildMainPage(html2send);
            break;

    case 2: idx = buildPortInfoPage(html2send,token[1]);
            break; 
    
        
    }
    
    
   //Now read fully assembled web page from html2send and send to the tcpip socket.
   if(idx > 0){
      data = 0;                           // Set socket for blocking
      ioctl(sock,FIONBIO,(char*)&data,sizeof(int));
    

      char* cp;
      int ecnt = 0;
      rc = 1;
      i = 0;
      while((rc > 0) && (i < idx) && html2send[i]){  //Loop until  rc shows an error or done
         cp = html2send[i++];                     //Get a char string pointer 
         rc = 0;
         ecnt = 0;
       
         rc = send(sock, cp, strlen(cp), 0);       //Send to blocking socket

             
      }
   } else{   //Error if page failed to assemble
      
    strcpy(szError,"HTTP/1.0 404 Not Found\nContent-Type: text/html\n\n<HTML><BODY>Unable to process request</BODY></HTML>\n");
        send(sock,szError,strlen(szError),0);
       
    }
    


    close(sock);

    //Free up all the memory we allocated
   
    
    for(i=0; i<idx; i++){
        if(html2send[i]) delete[] html2send[i];
    }
    delete[] html2send;

    pthread_exit(0);
    return NULL;  //To keep g++ and RH-7.x happy.
}



