#define Use_MsgBase
#define Use_LinkedList
#define Use_Handlers

//#define INCLUDE_REGIS

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <direct.h>
#include <ctype.h>
#include <tswin.hpp>
#include "proboard.hpp"
//#include "timebomb.h"
#include <dos.h>

long Message::lastIndex = 0;

static int port = PORT_VALUE;


bool do_modem(modem_response *);

// unsigned _stack = 12000;

extern unsigned _stklen = 13000;

#if __OVERLAY__
    unsigned _ovrbuffer = 0x800;
#endif

char *months_short[]      = { "???","Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
char *days_short[]        = { "Mon","Tue","Wed","Thu","Fri","Sat","Sun" };
char *days_full[]         = { "Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday" };
char *date_formats[]      = { "MM/DD/YY",   "YY/MM/DD",   "DD/MM/YY",   NULL };
char *date_formats_long[] = { "MM/DD/YYYY", "YYYY/MM/DD", "DD/MM/YYYY", NULL };

bool chatflag       = FALSE;
bool noyell_flag    = FALSE;
bool password_ok    = FALSE;
bool desqview       = FALSE;
bool stopped        = FALSE;
bool use_ems        = TRUE;
bool use_xms        = FALSE;
bool quiet          = FALSE;
bool echo_entered   = FALSE;
bool net_entered    = FALSE;

bool registered     = TRUE;
word max_node_count = 255;

bool menuchanged    = TRUE;
bool updatemenu     = TRUE;
bool reliable       = TRUE;
bool ignore_carrier = FALSE;
bool fatal          = FALSE;
bool no_hangup      = FALSE;
bool rip_detected   = FALSE;
bool sysop_next     = FALSE;

int  num_yells      = 0;
long totalcalls     = 0;
int  num_users      = 0;
int  time_limit     = 0;
int  time_removed   = 0;
int  node_number    = 1;
int  num_limits     = 0;
int  returnvalue    = 0;
int  display_mode   = 1;
int  event_due      = 10080;
byte org_videomode  = 0;
word org_numlines   = 0;
word min_level      = 0;
int  rip_screenlines= 0;
int  pastFirstUse   = 31;
bool newFilesChecked = FALSE;

int  download_limit = 0;
int  download_delay = 0;
word free_download  = 0;
word upload_needed  = 0;


String S_PRESS_ENTER_TO_CONTINUE;

byte current_color;

fossilio io;

BinLog lastcaller;

char user_firstname[36] = "";
char mypath[64]         = "";
char syspath[64]        = "";
char curmenu[9]         = "";
char page_reason[81]    = "";

User          user;
Config    far cfg;
usertimer     timer;
limits        limit[50];
KeyData       regis;
event         nextevent;

MarkedMsgList markedmsglist;

command_stack comstack;

LinkedList<PEXhandle> sysopkey_handlers;
LinkedList<PEXhandle> hangup_handlers;

Date login_date;
Time login_time;

int user_recnr = -1;

FileName FN_BINLOG_PB;
FileName FN_TIMELOG_PRO;
FileName FN_ONLINE_PRO;
FileName FN_MSGAREAS_PRO;
FileName FN_PVTFILES_PB;

MsgBaseList msgbase;

MsgBase *squishMsgBase;
MsgBase *hudsonMsgBase;
MsgBase *jamMsgBase;

char *EMPTY_STRING="";

extern "C" void cleanup();

extern void (*_new_handler)();

void nomemory();

static void _near init();
void readconfig();



#ifdef SOFTWARE_EXPIRE

//---------------------  
// Expire on 06/01/2000
//---------------------  

int BetaTooOld( void );

#endif



void
main(int argc,char *argv[])
{
   File     f;
   long     baud=0;
   int      i;
   FileName fn;

   bool standalone = FALSE;


/*#ifdef SOFTWARE_EXPIRE

     if ( BetaTooOld() )
     {
          printf( "\nThis software expired on %02d/%02d/%04d.  Contact TeleGrafix Communications at:\n\n",
                  EXPIRE_MONTH,
                  EXPIRE_DAY,
                  EXPIRE_YEAR );

          printf( "   http://www.telegrafix.com/products/proboard\n\n" );
          
          printf( "to obtain the latest version.\7\n" );
          printf( "\n" );

          sleep( 5 );

          exit( 1 );
     }

#endif */


   org_videomode = getvideomode();
   org_numlines  = tsw_vsize;

   for(i=1;i<argc;i++)
      if(argv[i][0]=='-' || argv[i][0]=='/')
         switch(toupper(argv[i][1]))
         {
            case 'B':
               baud = atol(&argv[i][2]);
               break;

            case 'P':
               port = atoi(&argv[i][2])-1;
               break;

            case 'N': node_number = atoi(&argv[i][2]);
               break;

            case 'Q':
               quiet       = TRUE;
               tsw_shutup  = TRUE;
               break;

            case 'E':
               set43();
               break;

            case 'V':
               {
                  int mode = atoi(&argv[i][2]);
                  if(mode>=3 && mode<=255)
                     setvideomode(mode);
               }
               break;

            case 'X':
               use_ems = FALSE;
               break;

            case 'I':
               ignore_carrier = TRUE;
               break;

            case 'S':
               standalone = TRUE;
               break;

            case 'A':
               reliable = TRUE;
               break;

            case 'L':
               min_level = unsigned(atol(&argv[i][2]));
               break;

            case 'T':
               event_due = atoi(&argv[i][2]);
               break;

            default :
               printf("\nUnknown option '-%c'\n",toupper(argv[i][1]));
               sleep(5);
         }

   if(_osmajor<3 || (_osmajor==3 && _osminor<30))
   {
      puts("\nDOS v3.30 or higher needed!");
      exit(1);
   }

#if __OVERLAY__
   if(use_ems)
      _OvrInitEms(0, 0, 0);

   if(use_xms)
      _OvrInitExt(0 ,0   );
#endif

   syspath[0]='\0';

   if(getenv("PROBOARD"))
   {
      strcpy(syspath,getenv("PROBOARD"));
      append_backspace(syspath);
   }

   if(!syspath[0])
   {
      fn(argv[0]);
      fn.stripName();

      strcpy(syspath,fn);
      append_backspace(syspath);
   }

   strupr(syspath);

   getcwd(mypath,59);
   append_backspace(mypath);

   check_exe(argv[0]);

   readconfig();

   if(!ReadLanguage(cfg.defaultLanguage))
   {
      fatalerror("Error reading default language files");
   }

   readconfig();

   FN_BINLOG_PB   (syspath,    "BINLOG.PB");
   FN_TIMELOG_PRO (syspath,    "TIMELOG.PRO" );
   FN_ONLINE_PRO  (syspath,    "ONLINE.PRO"  );
   FN_MSGAREAS_PRO(syspath,    "MESSAGES.PB" );
   FN_PVTFILES_PB (syspath,    "PVTFILES.PB ");

   _new_handler=nomemory;

   if(cfg.egamode) set43();

   if(tsw_videocard==EGA) tsw_vsize=*((byte _far *)0x484)+1;

   tsw_hsize = *((byte far *)0x44A);

   init();

   run_sdkfile("/I INIT");
   run_sdkfile("/I INIT_1");
   run_sdkfile("/I INIT_2");
   run_sdkfile("/I INIT_3");
   run_sdkfile("/I INIT_4");
   run_sdkfile("/I INIT_5");
   run_sdkfile("/I INIT_6");
   run_sdkfile("/I INIT_7");
   run_sdkfile("/I INIT_8");
   run_sdkfile("/I INIT_9");

   msgbase.add( squishMsgBase = new SquishMsgBase );
   msgbase.add( hudsonMsgBase = new HudsonMsgBase );
   msgbase.add( jamMsgBase    = new JamMsgBase    );

   if(standalone)
   {
      modem_response response;
      CLEAR_OBJECT(response);

      response.baud = baud;
      response.port = port;

      if(do_modem(&response))
      {
         baud = response.baud;
         port = response.port;
      }
      else
      {
         fatalerror("Modem initialization failed");
      }

      if(!baud) port = -1;
   }
   else
   {
      if(port<0 && baud)
         port = 0;
   }

   SCREEN.clear();
   SCREEN.attrib(15);

   SCREEN.change(1,1,tsw_hsize,tsw_vsize-1);

   update_user_window();

   if(baud || cfg.loglocal) LOG("-----------------------------------------------------");

   if(port<0)
      io.init(0,0);
   else
      io.init(port,baud);

   if(baud)
      LOG("Incoming call at %ld bps",baud);
   else
      LOG("Local login");

   atexit(cleanup);

   timer.start(20);

   update_display();

   if(nextevent.minutesleft()<=5 || (event_due<=5 && event_due>=0))
   {
      if(showansascrip("EVENTDUE") == ANS_NOFILE)
         io << '\n' << S_EVENT_HAS_TO_RUN << "\n\xFF";

      LOG("Event has to run");

      sleep(2);
      exit_proboard();
   }

   show_intro();

   if(login()) exit_proboard();

   LOG(1,"Calling from %s - Level %u",user.city,user.level);

   {
      user_online uo;
      uo.write();
   }

   for(i=0;i<strlen(user.name) && user.name[i]!=' ';i++)
      user_firstname[i] = user.name[i];

   user_firstname[i]=0;

   limit[0].level        = user.level;
   limit[0].timelimit    = 20;
   limit[0].daily_klimit = 0;

   fn(syspath,"LIMITS.PRO");

   if(!f.open(fn))
      file_error("LIMITS.PRO");
   else
   {
      num_limits = f.read(limit,50*sizeof(limits))/sizeof(limits);

      if(!num_limits)
         num_limits++;

      f.close();
   }

   adjust_limits();

   if(nextevent.minutesleft() < event_due)
      event_due = nextevent.minutesleft();

   if(event_due<=5 && event_due>=0)
   {
      LOG("Event has to run");
      io << '\n' << S_EVENT_HAS_TO_RUN << "\n\xFF";
      sleep(2);
      exit_proboard();
   }

   if(event_due>=0 && timer.left()>event_due-5)
   {
      LOG("Time limit adjusted from %d to %d minutes" , timer.left() , event_due-5);
      time_removed = timer.left() - event_due + 5;
      timer.changeleft(event_due-5);

      io << "\n\n" << S_UPCOMING_EVENT << "\n\n";
      io << S_PRESS_ENTER_TO_CONTINUE << '\n';
   }

   showansascrip("WELCOME");
   for(i=1;i<10;i++)
   {
      run_sdkfile(form("/I WELCOME%d",i));
      showansascrip(form("WELCOME%d",i));
   }

   run_sdkfile(form("/I SEC%u",user.level));
   showansascrip(form("SEC%u",user.level));

   switch(cfg.mailcheck)
   {
      case 2:
      {
         /*
         if(rip_mode)
         {
            rip_query("$COFF$");
            rip_query("$PHASER$");

            show_rip("_CHKMAIL");
         }
         else
         */
         {
            io << "\n" << S_CHECK_MAIL_PROMPT;
         }

         //if(rip_mode) io.show_remote = FALSE;
         bool resp = io.ask();
         //if(rip_mode) io.show_remote = TRUE;

         rip_query("$CON$");

         if(!resp) break;

         /*if(rip_mode) rip_reset();
                 else */io << '\n';
      }

      case 1:
         mailcheck();
         break;
   }

   rip_query("$CON$");

   io << '\n';

   showansascrip("NEWS");

   if(user.birthDate[0]==login_date[0] && user.birthDate[1]==login_date[1])
   {
      run_sdkfile("/I BIRTHDAY");
      showansascrip("BIRTHDAY");
   }

   menu_processor();
}



#ifdef SOFTWARE_EXPIRE

int BetaTooOld( void )
{
     struct dosdate_t d;


     _dos_getdate( & d );


     if ( 
          d.year  >= EXPIRE_YEAR   and
          d.month >= EXPIRE_MONTH  and
          d.day   >  EXPIRE_DAY 
        )
     {
          //---------------------
          // Software has expired
          //---------------------

          return( TRUE );
     }
     else
     {
          //---------------------------------------
          // Re-establish the proper starting port
          // number for ProBoard's COM port support
          //---------------------------------------

          port = -1;

          return( FALSE );
     }
}



#endif    // SOFTWARE_EXPIRE



void
readconfig()
{
   File f;
   FileName fn(syspath,"CONFIG.PRO");

   if(!f.open(fn))
   {
      file_error(fn , f.error());
   }
   else
   {
      if(f.len()!=sizeof(cfg) || f.read(&cfg,sizeof(cfg))!=sizeof(cfg))
         fatalerror(form("File <%s> is invalid." , (char *)fn));
   }

   f.close();

   if(memcmp(cfg.dateStampSignature,"ecwqnoiwef",10))
   {
      memcpy(cfg.dateStampSignature,"ecwqnoiwef",10);
      cfg.dateStamp.today();
      cfg.dateStampCrc = crc32(cfg.dateStampSignature,13);

      f.open(fn,fmode_create);
      f.write(&cfg,sizeof(cfg));
      f.close();
   }

   if(cfg.dateStampCrc != crc32(cfg.dateStampSignature,13))
   {
      pastFirstUse = 61;
   }
   else
   {
      pastFirstUse = Date(TODAY) - cfg.dateStamp;
   }

   if(!cfg.defaultLanguage[0])
      strcpy(cfg.defaultLanguage,"ENGLISH");

   if(pb_curlang.menuPath[0])
      strcpy(cfg.mnupath , pb_curlang.menuPath);

   if(pb_curlang.txtPath[0])
      strcpy(cfg.txtpath , pb_curlang.txtPath);

   append_backspace(cfg.txtpath);
   append_backspace(cfg.RIPpath);
   append_backspace(cfg.iconspath);
   append_backspace(cfg.mnupath);
   append_backspace(cfg.msgpath);
   append_backspace(cfg.uploadpath);
   append_backspace(cfg.pexpath);
   append_backspace(cfg.pvtuploadpath);
   append_backspace(cfg.nodelistdir);

   if(cfg.pwdchar == '\0') cfg.pwdchar = '#';

   if(cfg.numnodes>1) cfg.multiline = TRUE;

   if(cfg.IObuffersize < 1 || cfg.IObuffersize > 9999)
      cfg.IObuffersize = 1;

   User::setDir(cfg.msgpath);
}

static void near
init()
{
     //----------------------------  
     // JDR: REGISTRATION REFERENCE
     //----------------------------  
     
     if ( registered  ||
          max_node_count != 2 )
     {
          //-------------------------------------
          // Someone tampered with the .EXE file,
          // trying to hardcode these values
          //-------------------------------------

          //exit_proboard();
     }


     //CHECK_REG();


/*#ifdef KEY_NEEDED

     if ( ! registered )
     {
          LOG( "This version does not work in unregistered mode" );
      
          exit_proboard();
     }

#endif */


     //-------------------------------------  
     // Check the node count of this license
     //-------------------------------------  

     /*if ( registered )
     {
          if ( max_node_count != 0 )
          {
               //-----------------------------------------------------------  
               // We have a distinct node count.  Are we within our license?
               //-----------------------------------------------------------  

               if ( node_number > max_node_count )
               {
                    //-----------------  
                    // License exceeded
                    //-----------------  

                    fatalerror( form( "Node license exceeded.  Tried to load node %d (%d allowed)",
                                      (int) node_number,
                                      (int) max_node_count ) );

                    exit_proboard();
               }

          }
     }
     else
     {
          //--------------------------------------------------  
          // Unregistered version -- only allow two nodes max!
          //--------------------------------------------------  

          if ( node_number > MAX_UNREG_NODES )
          {
               fatalerror( form( "Unregistered versions cannot start more than %d nodes", MAX_UNREG_NODES ) );

               exit_proboard();
          }
     }*/


     if ( tsw_OS == OS_DESQVIEW ) 
     {
          desqview = TRUE;
     }


     timelog tl;


     tl.read();

     totalcalls = tl.totalcalls;


     File f;


     if ( f.open( FN_BINLOG_PB ) )
     {
          if ( f.len()  >=  sizeof( BinLog ) )
          {
               f.seek( f.len() - sizeof( BinLog ) );

               f.read( & lastcaller,  sizeof( lastcaller ) );
          }


          f.close();
     }


     event e;

     memset( & nextevent,
             0,
             sizeof( nextevent ) );


     if ( f.open( FileName( syspath, "EVENTS.PRO" ) ) )
     {
          for(;;)
          {
               if ( f.read( & e,  sizeof( e ) )  !=  sizeof( e ) )
               {
                    break;
               }

               if ( e.minutesleft()  <=  nextevent.minutesleft() )
               {
                    nextevent = e;
               }
          }
     }


     num_users  =  int( User::numUsers() );

  // user.gentops();
}




