#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <fcntl.h>
#include <fctype.h>
#include <sys/stat.h>
#include <exec/types.h>
#include <libraries/dosextens.h>
#include <graphics/gfxbase.h>
#include <graphics/text.h>

#include <devices/tpt.h>

#include <dlg/msg.h>
#include <dlg/log.h>
#include <dlg/resman.h>
#include <dlg/user.h>
#include <dlg/portconfig.h>

#include <dlg_private/dlg.h>
#include <dlg_private/crypt.h>

#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/diskfont.h>
#include <proto/graphics.h>
#include <proto/dlg.h>

#include <pragmas/dlg.h>

static char version[]="$VER: Setup 2.1 © 1995-1997 by DLG Development "__AMIGADATE__"";

void  main      (int, char **);
void  sendstring(char *);
void  readstring(BPTR, char *);
void _CXBRK     (void);
void  CleanUp   (char *);
void  CLine     (BPTR);
BOOL  RChar     (BPTR);

BPTR            sout;
struct Library *DiskfontBase = NULL;
struct GfxBase *GfxBase      = NULL;
struct Library *DLGBase      = NULL;
char          **SA;

BPTR   ofh  = NULL;
BPTR   ifh  = NULL;

struct Global_Settings Globals;
struct Port            MyPort;
struct Modem           MyModem;
struct Displays        MyDisplay;
struct Ram_File        RStruct;

char         port [4];
char         dbstr[80];
char         debug   =   0;
char         noname  =   0;
UBYTE        spawned = TRUE;


void main(int argc, char *argv[])

{long    a;

 char  **s;
 char    modem [80];
 char    handle[80];
 char    executestring[128];
 char    log[24];
 char    bc [25];
 char    filename[80];

 struct TextAttr  tAttr;
 struct TextFont *tFont;

 sout = Output();

 spawned = FALSE;

 if (!(DLGBase=OpenLibrary(DLGNAME, DLGVERSION)))
     CleanUp("Unable to open DLG.library");

 if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 33L)))
     CleanUp("Unable to open graphics.library");

 if (!(DiskfontBase = OpenLibrary("diskfont.library", 33L)))
     CleanUp("Unable to open diskfont.library");

 if(argc < 2)  CleanUp("Bad arguments");
 if(argc > 2)
   {s = &argv[2];
    while(*s)
         {if (!Stricmp(*s, "-n"))
              noname++;
            else
              debug++;

          *s++;
         }
   }

 strncpy(port, argv[1], 3);
 port[3]='\0';
 ASPrintf(NULL, handle, "%s:", port);

 ASPrintf(NULL, filename, "DlgConfig:Port/%s.port", port);
 if (GetFirstStruct(filename, (char *)&MyPort, sizeof(MyPort))==-1)
     CleanUp("Unable to read port configuration");

 ASPrintf(NULL, filename, "DlgConfig:Port/%s", MyPort.GlobalFile);
 if (GetFirstStruct(filename, (char *)&Globals, sizeof(Globals))==-1)
     CleanUp("Unable to read globals");

 ASPrintf(NULL, filename, "DlgConfig:Port/%s", MyPort.ModemFile);
 if (GetFirstStruct(filename, (char *)&MyModem, sizeof(MyModem))==-1)
     CleanUp("Unable to read modem configuration");

 ASPrintf(NULL, filename, "DlgConfig:Port/%s", MyPort.DisplayFile);
 if (GetFirstStruct(filename, (char *)&MyDisplay, sizeof(MyDisplay))==-1)
     CleanUp("Unable to read display configuration");

 if (Globals.DefaultScreen)
    {tAttr.ta_Name  = (UBYTE *)MyDisplay.Screen.fontname;
     tAttr.ta_YSize =  MyDisplay.Screen.fontsize;
    }
  else
    {tAttr.ta_Name  = (UBYTE *)MyDisplay.Window.fontname;
     tAttr.ta_YSize =  MyDisplay.Window.fontsize;
    }
 tAttr.ta_Style = FS_NORMAL;
 tAttr.ta_Flags = FPF_ROMFONT|FPF_DISKFONT|FPF_DESIGNED;
 if ((tFont=(struct TextFont *)OpenDiskFont(&tAttr)))
      CloseFont(tFont);

 ASPrintf(NULL, bc, "DLG:TKill -p %s -f", port);
 if (ImmedLockPort(port,"Setup","Setup - Waiting for call",-1,bc)!=RMNOERR)
     CleanUp("Unable to lock port");

 ASPrintf(NULL, filename, "%s%s/%d", handle, MyPort.Device, MyPort.Unit);
 if (MyModem.Lock)
     strcat(filename,"/7");
   else
     strcat(filename,"/0");

 Delay(100L);

// DB("Attempting to open handler's input stream");

 for(a = 0; a < 5; a++)
    {
      if (!(ifh = Open(filename, MODE_OLDFILE)))
      {
         Delay(50L);
      }
       else
         break;
    }
 if (a == 5)  CleanUp("Unable to open handler for input");

// DB("Attempting to open handler's output stream");

 if (!(ofh = Open(filename, MODE_NEWFILE)))
     CleanUp("Unable to open handler for output");


 /* !!! Important that this line happens before any other handler commands !!! */
 SendCtlMsg(TVERSION, (long)CRYPTOFFSET, port);


 TUnSetFlags(T_DO_TIMEOUT | T_BREAK | T_PAUSE,  port);
 TSetFlags  (T_RAW,                             port);
 TBaud      (MyModem.MaxBaud,port);

 sendstring(MyModem.Reset);
 sendstring("\n");
 Delay(100);
 
 sendstring(MyModem.Init);
 sendstring("\n");
 Delay(50);

 while(TRUE)
      {readstring(ifh, modem);

       if (MyModem.AnswerMethod)
           if (!Strnicmp(modem,MyModem.Ring,4))
              {sendstring(MyModem.Answer);
               sendstring("\n");
              }

       if (!Strnicmp(modem, "CONNECT", 7))  break;

       if (!Stricmp(modem, "LOCAL"))
          {Write(ofh, "Local Connect\n\n", 15L);
           strcpy(modem, "CONNECT 19200");
           break;
          }
      }

 TransferPortLock(port,"Setup","BBS","User online",0,"");

 sscanf(modem, "CONNECT %ld", &RStruct.Baud_Rate);
 if (!RStruct.Baud_Rate)
    {if (!Strnicmp(modem,"CONNECT FAST",12))
          RStruct.Baud_Rate = 19200L;
        else
          RStruct.Baud_Rate =   300L;
    }

 strcpy(RStruct.Name, "User Logging In");
 RStruct.status = 0L;
 WriteRam(&RStruct,port); 
 Delay((long)(50*Globals.ConnectDelay));

 if (Globals.GlobalScreen)
    {if (!Globals.DefaultScreen)
         TWindow(WOPEN,      &MyDisplay.Window, port);
       else
         TScreen(TPOPSCREEN, &MyDisplay.Screen, port);
    }

 if (!MyModem.Lock)
    {if(debug)  DB("Using link rate");
     TBaud(RStruct.Baud_Rate, port);
    }

 CLine(ifh);
 Close(ifh);
 ifh = 0;

 ASPrintf(NULL, log, "[%ld] Baud", RStruct.Baud_Rate);
 WriteLog(CONNECT, "System", port, log);

 TSetFlags(T_DO_PEND | T_KILL_ENABLE | T_PAUSE | T_DO_TIMEOUT,port);
 TTimeDelay((long)Globals.TimeOut * 20L, port);

 if(Globals.VerbPause)
   TSetFlags(T_VERB_PAUSE,   port);
 else
   TUnSetFlags(T_VERB_PAUSE, port);


 if (noname)
     SendCtlMsg(TVERSION, -1, port);
   else
     SendCtlMsg(TVERSION, -2, port);

 ASPrintf(NULL, executestring, "newcli %s%s/%d%s from DLGCONFIG:Batch/%s.startup",handle,MyPort.Device,MyPort.Unit,(MyModem.Lock)?"/7":"",port);
 if (debug)  DB(executestring);

 spawned = TRUE;
 Execute(executestring, 0L, 0L);
 CleanUp(NULL);
}


void sendstring(char *modem)

{if (debug)
    {ASPrintf(NULL, dbstr, "Sending String: %s", modem);
     DB(dbstr);
    }

 while(*modem)
      {if (*modem == '|')  *modem = '\n';

       if (*modem == '\\')
          {modem++;
           if (*modem == 'w')
              {Delay(100L);
               modem++;
               continue;
              }
          }

       Delay(5L);
       Write(ofh, modem, 1L);
       modem++;
      }
}


void readstring(BPTR fh, char *string)

{char a;
 long b = 0;

 string[0] = 0;

 while(Read(fh, &a, 1L) == 1L)
      {a &= 127;
       chkabort();
       if (a==10 || a==13)
          {string[b] = '\0';
           break;
          }

       string[b] = a;
       if (b<79)  b++;
      }

 chkabort();
 if (debug)
    {ASPrintf(NULL, dbstr, "Read String: %s", string);
     DB(dbstr);
    }
}


void _CXBRK(void)

{CleanUp(NULL);
}


void CleanUp(char *s)

{if (ofh)           Close(ofh);
 if (ifh)           Close(ifh);

 if (s)             AFPrintf(NULL,sout,"\n Setup Error: %s\n\n",s);
 if (DiskfontBase)  CloseLibrary(DiskfontBase);
 if (GfxBase)       CloseLibrary((struct Library *)GfxBase);
 if (DLGBase)       CloseLibrary(DLGBase);

 if (!spawned)      FreePort(port, "Setup");

 exit(s?5:0);
}


void CLine(BPTR ifh)

{for(;;)
    {Delay(20L);
     if (!RChar(ifh))  break;
     while(RChar(ifh));
    }
}


BOOL RChar(BPTR ifh)

{char dummy;

 if (WaitForChar(ifh, 0L))
    {Read(ifh, &dummy, 1L);
     return(TRUE);
    }

 return(FALSE);
}
