/*********************************************************************** 
 * AUTODIAL V1.2  by: Leonardo Fei, via Fava 6, 20125 Milano, Italy.
 * Special thanks to THE SOFTWARE DISTILLERY for the POPCLI code, which
 * helped me to understand many useful things.
 * This code requires Kickstart V1.2 or above and is guarranteed to work
 * on Amiga 500,1000,2000.  Please use the -cc option with Lattice lc2
 * second pass compiler (or -ac with lc) to make sure that Gadgets data
 * is placed in CHIP_MEM.  You could, otherwise, use the FixHunk program,
 * from AmigaLibraryDisk 36 by Fred Fish, on the executable file.
 */

#include <exec/types.h>
#include <exec/tasks.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/execbase.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <exec/io.h>
#include <exec/interrupts.h>
#include <exec/devices.h>
#include <exec/libraries.h>
#include <devices/serial.h>
#include <devices/input.h>
#include <devices/inputevent.h>
#include <devices/timer.h>
#include <graphics/gfxbase.h>
#include <libraries/dos.h>
#include <intuition/intuition.h>
#include <stdio.h>

#define SCRHEIGHT  94  /* Screen Height */
#define INPUT_SIZE 50      /* Size of Input Event ring buffer */

#define LEFT_AMIGA      0x8040  /* Left-Amiga event qualifier */
#define DIAL    0x22  /* raw key D */
#define HANGUP  0x25  /* raw key H */
#define ONLINE  0x18  /* raw key O */
#define QUIT    0x10  /* raw key Q */
#define DTR     0x80  /* bit 7 of SerialPort */
#define RTS     0X40  /* bit 6 of SerialPort */ 
#define CD      0x20  /* bit 5 of SerialPort */ 
#define CTS     0x10  /* bit 4 of SerialPort */
#define DSR     0x08  /* bit 3 of SerialPort */

#define MODEM  *pser  /* pointer to SerialRegister at #$BFD000 */
#define ACTIVE  0     /* SerialPort bits are active low        */

/*  Globals */

struct MsgPort    *InputDevPort      = 0;
struct IOStdReq   *InputRequestBlock = 0;
struct Interrupt  handlerStuff;
APTR TimerBase;
int timeout;

extern struct timerequest *CreateTimer();
extern struct MsgPort *CreatePort();
extern struct IORequest *CreateExtIO();
struct timeval currentval;
unsigned char *pser, oldstate;

int               InputDeviceOpen = 0; /* Just to keep track of things      */
struct MemEntry   me[10];          /* Dummy data used to keep the handler   */
                                   /* happy                                 */
struct InputEvent EventRing;       /* Raw key event buffer                */
int               MainSignal;      /* Used by handler to wakeup main task */
int               Waiting = 0;     /* Set by main before going to sleep   */
struct Task       *MainTask;

extern struct GfxBase *GfxBase;
struct Device *ConsoleDevice = 0;

extern VOID HandlerInterface();

struct Window *window;
struct Screen *screen;
struct IntuitionBase *IntuitionBase;
struct IntuiMessage *message;

struct TextAttr MyFont = {
   "topaz.font",
   TOPAZ_EIGHTY,
   FS_NORMAL,
   FPF_ROMFONT,
};
   
UBYTE SIBuffer4[3] =
   "15";

struct StringInfo GadgetSI4 = {
   SIBuffer4,  /* buffer where text will be edited */
   NULL,   /* optional undo buffer */
   0,  /* cursor position in buffer */
   3, /* maximum number of characters to allow(+'\0'!) */
   0,  /* first displayed character buffer position */
   0,0,0,0,0,  /* Intuition initialized and maintained variables */
   0,  /* Rastport of gadget */
   NULL,   /* initial value for integer gadgets */
   NULL    /* alternate keymap (fill in if you set the flag) */
};

USHORT BorderVectors4[] = {0,0,33,0,33,13,0,13,0,0};
struct Border Border4 = {
   -5,-3,  /* border XY origin relative to container TopLeft */
   3,0,JAM1,   /* front pen, back pen and drawmode */
   5,  /* number of XY vectors */
   BorderVectors4, /* pointer to XY vectors */
   NULL    /* next border in list */
};

struct IntuiText IText4 = {
   1,0,JAM1,   /* front and back text pens and drawmode */
   -105,0,   /* XY origin relative to container TopLeft */
   &MyFont,   /* font pointer or NULL for defaults */
   "CD timeout:",   /* pointer to text */
   NULL    /* next IntuiText structure */
};

struct Gadget Gadget4 = {
   NULL,   /* next gadget */
   130,54,  /* origin XY of hit box relative to window TopLeft */
   30,11, /* hit box width and height */
   GADGHCOMP,  /* gadget flags */
   NULL,   /* activation flags */
   STRGADGET,  /* gadget type */
   (APTR)&Border4, /* gadget border or image to be rendered */
   NULL,   /* alternate imagery for selection */
   &IText4,    /* first IntuiText structure */
   0,  /* gadget mutual-exclude long word */
   (APTR)&GadgetSI4,   /* SpecialInfo structure for string gadgets */
   4,  /* user-definable data (ordinal gadget number) */
   NULL    /* pointer to user-definable data */
};

UWORD cancelon[180] = {
/* Bit Plane #0 */

   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFE,0x0000,
   0xC000,0x0000,0x0000,0x0000,0x0006,0x0000,
   0xDFE0,0x0000,0x0000,0x0000,0x0006,0x0000,
   0xDFE0,0x7C00,0x0000,0x0000,0x1C06,0x0000,
   0xDFE0,0xC600,0x0000,0x0000,0x0C06,0x0000,
   0xCFE1,0x803E,0x0FC1,0xF07C,0x0C06,0x0000,
   0xC001,0x8003,0x0C63,0x18C6,0x0C06,0x0000,
   0xC001,0x801F,0x0C63,0x00FE,0x0C06,0x0000,
   0xC000,0xC663,0x0C63,0x18C0,0x0C06,0x0000,
   0xC000,0x7C3D,0x8C61,0xF07C,0x1E06,0x0000,
   0xC000,0x0000,0x0000,0x0000,0x0006,0x0000,
   0xC000,0x0000,0x0000,0x0000,0x0006,0x0000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFE,0x0000,
   0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
   0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,

/* Bit Plane #1 */

   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFE,0x0000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xE03F,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xE03F,0x83FF,0xFFFF,0xFFFF,0xE3FF,0xE000,
   0xE03F,0x39FF,0xFFFF,0xFFFF,0xF3FF,0xE000,
   0xFFFE,0x7FC1,0xF03E,0x0F83,0xF3FF,0xE000,
   0xFFFE,0x7FFC,0xF39C,0xE739,0xF3FF,0xE000,
   0xFFFE,0x7FE0,0xF39C,0xFF01,0xF3FF,0xE000,
   0xFFFF,0x399C,0xF39C,0xE73F,0xF3FF,0xE000,
   0xFFFF,0x83C2,0x739E,0x0F83,0xE1FF,0xE000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0x3FFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0x3FFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000
};

UWORD canceloff[180] = {
/* Bit Plane #0 */

   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFE,0x0000,
   0xC000,0x0000,0x0000,0x0000,0x0006,0x0000,
   0xC020,0x0000,0x0000,0x0000,0x0006,0x0000,
   0xC020,0x7C00,0x0000,0x0000,0x1C06,0x0000,
   0xC020,0xC600,0x0000,0x0000,0x0C06,0x0000,
   0xCFE1,0x803E,0x0FC1,0xF07C,0x0C06,0x0000,
   0xC001,0x8003,0x0C63,0x18C6,0x0C06,0x0000,
   0xC001,0x801F,0x0C63,0x00FE,0x0C06,0x0000,
   0xC000,0xC663,0x0C63,0x18C0,0x0C06,0x0000,
   0xC000,0x7C3D,0x8C61,0xF07C,0x1E06,0x0000,
   0xC000,0x0000,0x0000,0x0000,0x0006,0x0000,
   0xC000,0x0000,0x0000,0x0000,0x0006,0x0000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFE,0x0000,
   0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
   0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,

/* Bit Plane #1 */

   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFE,0x0000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0x3FFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000,
   0x3FFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xE000
};

struct Image Cancel_on = {
   0,0,
   83,15,2,
   &cancelon[0],
   0x3,0x0,
   NULL,
};

struct Image Cancel_off = {
   0,0,
   83,15,2,
   &canceloff[0],
   0x3,0x0,
   NULL,
};

struct Gadget Gadget3 = {
   &Gadget4,   /* next gadget */
   97,32,  /* origin XY of hit box relative to window TopLeft */
   79,13,  /* hit box width and height */
   GADGHIMAGE | GADGIMAGE,  /* gadget flags */
   GADGIMMEDIATE | RELVERIFY,  /* activation flags */
   BOOLGADGET, /* gadget type */
   (APTR)&Cancel_off, /* gadget border or image to be rendered */
   (APTR)&Cancel_on,   /* alternate imagery for selection */
   NULL,    /* first IntuiText structure */
   0,  /* gadget mutual-exclude long word */
   NULL,   /* SpecialInfo structure for string gadgets */
   3,  /* user-definable data (ordinal gadget number) */
   NULL    /* pointer to user-definable data */
};

UWORD dialon[150] = {
/* Bit Plane #0 */

   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xC000,
   0xC000,0x0000,0x0000,0x0000,0xC000,
   0xDFE0,0x0000,0x0000,0x0000,0xC000,
   0xDFE0,0x7E03,0x0000,0x7000,0xC000,
   0xDFE0,0x3300,0x0000,0x3000,0xC000,
   0xCFE0,0x3187,0x03E0,0x3000,0xC000,
   0xC000,0x3183,0x0030,0x3000,0xC000,
   0xC000,0x3183,0x01F0,0x3000,0xC000,
   0xC000,0x3303,0x0630,0x3000,0xC000,
   0xC000,0x7E07,0x83D8,0x7800,0xC000,
   0xC000,0x0000,0x0000,0x0000,0xC000,
   0xC000,0x0000,0x0000,0x0000,0xC000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xC000,
   0x0000,0x0000,0x0000,0x0000,0x0000,
   0x0000,0x0000,0x0000,0x0000,0x0000,

/* Bit Plane #1 */

   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xC000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xE03F,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xE03F,0x81FC,0xFFFF,0x8FFF,0xFC00,
   0xE03F,0xCCFF,0xFFFF,0xCFFF,0xFC00,
   0xFFFF,0xCE78,0xFC1F,0xCFFF,0xFC00,
   0xFFFF,0xCE7C,0xFFCF,0xCFFF,0xFC00,
   0xFFFF,0xCE7C,0xFE0F,0xCFFF,0xFC00,
   0xFFFF,0xCCFC,0xF9CF,0xCFFF,0xFC00,
   0xFFFF,0x81F8,0x7C27,0x87FF,0xFC00,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0x3FFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0x3FFF,0xFFFF,0xFFFF,0xFFFF,0xFC00
};

UWORD dialoff[150] = {
/* Bit Plane #0 */

   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xC000,
   0xC000,0x0000,0x0000,0x0000,0xC000,
   0xC020,0x0000,0x0000,0x0000,0xC000,
   0xC020,0x3F01,0x8000,0x3800,0xC000,
   0xC020,0x1980,0x0000,0x1800,0xC000,
   0xCFE0,0x18C3,0x81F0,0x1800,0xC000,
   0xC000,0x18C1,0x8018,0x1800,0xC000,
   0xC000,0x18C1,0x80F8,0x1800,0xC000,
   0xC000,0x1981,0x8318,0x1800,0xC000,
   0xC000,0x3F03,0xC1EC,0x3C00,0xC000,
   0xC000,0x0000,0x0000,0x0000,0xC000,
   0xC000,0x0000,0x0000,0x0000,0xC000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xC000,
   0x0000,0x0000,0x0000,0x0000,0x0000,
   0x0000,0x0000,0x0000,0x0000,0x0000,

/* Bit Plane #1 */

   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xC000,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0x3FFF,0xFFFF,0xFFFF,0xFFFF,0xFC00,
   0x3FFF,0xFFFF,0xFFFF,0xFFFF,0xFC00
};

struct Image Dial_on = {
   0,0,
   70,15,2,
   &dialon[0],
   0x3,0x0,
   NULL,
};

struct Image Dial_off = {
   0,0,
   70,15,2,
   &dialoff[0],
   0x3,0x0,
   NULL,
};

struct Gadget Gadget2 = {
   &Gadget3,   /* next gadget */
   10,32,  /* origin XY of hit box relative to window TopLeft */
   66,13,  /* hit box width and height */
   GADGHIMAGE | GADGIMAGE,  /* gadget flags */
   RELVERIFY,  /* activation flags */
   BOOLGADGET, /* gadget type */
   (APTR)&Dial_off, /* gadget border or image to be rendered */
   (APTR)&Dial_on,   /* alternate imagery for selection */
   NULL,    /* first IntuiText structure */
   0,  /* gadget mutual-exclude long word */
   NULL,   /* SpecialInfo structure for string gadgets */
   2,  /* user-definable data (ordinal gadget number) */
   NULL    /* pointer to user-definable data */
};

UBYTE SIBuffer1[20] =
   "8559";
struct StringInfo GadgetSI1 = {
   SIBuffer1,  /* buffer where text will be edited */
   NULL,   /* optional undo buffer */
   4,  /* cursor position in buffer */
   20, /* maximum number of characters to allow */
   0,  /* first displayed character buffer position */
   0,0,0,0,0,  /* Intuition initialized and maintained variables */
   0,  /* Rastport of gadget */
   NULL,   /* initial value for integer gadgets */
   NULL    /* alternate keymap (fill in if you set the flag) */
};

USHORT BorderVectors1[] = {0,0,169,0,169,13,0,13,0,0};
struct Border Border1 = {
   -5,-3,  /* border XY origin relative to container TopLeft */
   3,0,JAM1,   /* front pen, back pen and drawmode */
   5,  /* number of XY vectors */
   BorderVectors1, /* pointer to XY vectors */
   NULL    /* next border in list */
};

struct Gadget Gadget1 = {
   &Gadget2,   /* next gadget */
   15,17,  /* origin XY of hit box relative to window TopLeft */
   165,11, /* hit box width and height */
   GADGHCOMP | SELECTED,  /* gadget flags */
   RELVERIFY,   /* activation flags */
   STRGADGET,  /* gadget type */
   (APTR)&Border1, /* gadget border or image to be rendered */
   NULL,   /* alternate imagery for selection */
   NULL,    /* first IntuiText structure */
   0,  /* gadget mutual-exclude long word */
   (APTR)&GadgetSI1,   /* SpecialInfo structure for string gadgets */
   1,  /* user-definable data (ordinal gadget number) */
   NULL    /* pointer to user-definable data */
};

/* Gadget list */

struct NewWindow newwindows = {
   225,15, /* window XY origin relative to TopLeft of screen */
   190,70, /* window width and height */
   2,1,    /* detail and block pens */
   GADGETUP | GADGETDOWN,   /* IDCMP flags */
   ACTIVATE | WINDOWDRAG | RMBTRAP,   /* other window flags */
   &Gadget1,   /* first gadget in gadget list */
   NULL,   /* custom CHECKMARK imagery */
   "                       ",  /* window title */
   NULL,   /* custom screen */
   NULL,   /* custom bitmap */
   NULL,NULL,    /* minimum width and height */
   NULL,NULL,    /* maximum width and height */
   CUSTOMSCREEN    /* destination screen type */
};

struct NewScreen newscreens = {
   0,100,   /* left, top edges */
   640,85,2,   /* width, height, depth */
   2,1,   /* detail, block pens */
   HIRES,   /* viewmodes */
   CUSTOMSCREEN,   /* screen type */
   &MyFont,   /* font type */
   "AutoDial  V1.2  by Leonardo Fei.  Press LeftAmiga-D to call up AutoDial.",
   NULL,   /* gadgets */
   NULL    /* custombitmap */
};
   

/****************************************************************************/

void main(argc,argv)
int argc;
char *argv[];
{ 
 void  CleanUp_Exit(), WaitForTimer(), DeleteTimer(), Dial(), pause();
 void  DialNumber(), show_go();
 UWORD  Qualifier, Code;
 int dum;

 pser = 0xbfd000;  /* Serial Port Register location */
 GfxBase = 0;  /* For cleanup purposes */
 
 IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
    if (IntuitionBase == NULL)  CleanUp_Exit(FALSE);
 
 /* Open the Gfx library, since it's needed to do the WaitTOF()'s in the
    input handler */
 if ((GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)) == NULL)
    CleanUp_Exit(FALSE);
    
 newscreens.TopEdge = (GfxBase->NormalDisplayRows)+3;
 if ((screen = (struct Screen *)OpenScreen(&newscreens)) == NULL)
    CleanUp_Exit(FALSE);
 newwindows.Screen = screen;
 
 if (argc > 1)
    sprintf(SIBuffer1,"%s",argv[1]);
 if (argc > 2)
    {
    timeout = atoi(argv[2]);
    sprintf(SIBuffer4,"%2d",timeout);
    }
 else
    timeout = atoi(SIBuffer4);
 if ((argc > 3) && (argv[3][0] == '-') && (argv[3][1] == 'i'))   
    {
    ScreenToFront(screen);  /* brings AD screen on top of any other */
    if ((window = (struct Window *)OpenWindow(&newwindows)) == NULL)
       CleanUp_Exit(FALSE);
    for (dum = 0; dum < (SCRHEIGHT + 2); dum += 2)
       MoveScreen(screen,NULL,-2);  /* scrolls up AD screen */
    Gadget2.Flags |= SELECTED;
    RefreshGadgets(&Gadget2,window,NULL);
    DialNumber();
    show_go();
    while(screen->TopEdge < (GfxBase->NormalDisplayRows)+3)
       MoveScreen(screen,NULL,2);
    CloseWindow(window);
    CleanUp_Exit(TRUE);
    }
 
 /* Open the console device. This will return the InputRequestBlock
    whose field io_Device is initialized to the library pointer. */
 if (OpenDevice("console.device",-1,InputRequestBlock,0) != 0)
    exit(FALSE);
    
 ConsoleDevice = InputRequestBlock->io_Device;
 CloseDevice(InputRequestBlock);
 InputRequestBlock = 0; /* For clean up purposes */

 /* Get a signal bit so that our input handler can wake us up when there is 
    something in the buffer */
 MainSignal = AllocSignal(-1);
 MainTask   = (struct Task *)FindTask(0);

 /* Get a port for the input device ... */
 if ((InputDevPort = (struct MsgPort *)CreatePort(0,0)) == NULL)
    CleanUp_Exit(FALSE);

 /* ... and an InputRequestBlock */
 if ((InputRequestBlock = (struct IOStdReq *)CreateStdIO(InputDevPort)) == NULL)
    CleanUp_Exit(FALSE);

 /* Open the input device */
 if (OpenDevice("input.device",0,InputRequestBlock,0) == NULL)
    InputDeviceOpen = 1;
 else
    CleanUp_Exit(FALSE);

 /* Get ready to install our own device handler ... */
 handlerStuff.is_Data = (APTR)&me[0];
 handlerStuff.is_Code = HandlerInterface;
 handlerStuff.is_Node.ln_Pri = 51;

 InputRequestBlock->io_Command = IND_ADDHANDLER;
 InputRequestBlock->io_Data    = (APTR)&handlerStuff;
 
 /* ... and install the handler */
 DoIO(InputRequestBlock);
 
 /* Call the main control routine and sit there until the user requests to 
    quit. */

 while (1)
    {
    Waiting = 1;  
    Wait(1<<MainSignal);

    Qualifier = EventRing.ie_Qualifier;
    Code = EventRing.ie_Code;

    /* User requested to quit ? */
    if (Qualifier == LEFT_AMIGA && Code == QUIT)
       CleanUp_Exit(TRUE);

    if (Qualifier == LEFT_AMIGA && Code == DIAL)
       {
       oldstate = MODEM;
       if ((MODEM & DTR) != ACTIVE)
          MODEM ^= DTR;  /* DTR ACTIVE to force response (DSR) from modem */
       ScreenToFront(screen);  /* brings AD screen on top of any other */
       if ((window = (struct Window *)OpenWindow(&newwindows)) == NULL)
          CleanUp_Exit(FALSE);
       if ((MODEM & DSR) != ACTIVE)
          {
          SetWindowTitles(window,"Modem not responding !!",-1);
          OffGadget(&Gadget2,window,NULL);
          }
       else 
          {
          SetWindowTitles(window,"Modem ready to operate.",-1);
          OnGadget(&Gadget2,window,NULL);
          ActivateGadget(&Gadget1,window,NULL);
          }
       for (dum = 0; dum < (SCRHEIGHT + 2); dum += 2)
          MoveScreen(screen,NULL,-2);  /* scrolls up AD screen */
       MODEM = oldstate;
       for (;;)  /* wait for user action on gadgets */
          {
          WaitPort(window->UserPort);
          if (message = (struct IntuiMessage *)GetMsg(window->UserPort))
             {
             ReplyMsg(message);
             switch (message->Class)
                {
  case GADGETUP     : Gadget2.Flags |= SELECTED;
                      RefreshGadgets(&Gadget2,window,NULL);
                      timeout = atoi(SIBuffer4);
                      DialNumber();
                      show_go();
                      while(screen->TopEdge < (GfxBase->NormalDisplayRows)+3)
                         MoveScreen(screen,NULL,2);
                      CloseWindow(window);
                      goto continuous;
  case GADGETDOWN   : while(screen->TopEdge < (GfxBase->NormalDisplayRows)+3)
                         MoveScreen(screen,NULL,2);
                      CloseWindow(window);
                      MODEM = oldstate;
                      goto continuous;
                } /* switch */
             } /* if */
          } /* for -loop infinite- */
       } /* if LeftAmiga-D */
       if (Qualifier == LEFT_AMIGA && Code == HANGUP)
          MODEM |= (DTR|RTS);  /* hangup the telephone line */
       if (Qualifier == LEFT_AMIGA && Code == ONLINE &&
                                        ((MODEM & DTR) != ACTIVE))
          MODEM ^= (DTR|RTS);  /* go online! */
       continuous: 
      } /* while loop infinite */
} /* end of main */

/****************************************************************************/

void CleanUp_Exit(exitlevel)

/* Clean up all allocated resources and exit */

int exitlevel;

{
 /* Remove our input handler and device from the chain */ 
 if (InputRequestBlock)
    {
     InputRequestBlock->io_Command = IND_REMHANDLER;
     InputRequestBlock->io_Data    = (APTR)&handlerStuff;
     DoIO(InputRequestBlock);
     
     if (InputDeviceOpen)
        CloseDevice(InputRequestBlock);

     DeleteStdIO(InputRequestBlock);
    }

 if (InputDevPort)
    DeletePort(InputDevPort);

 if (GfxBase)
    CloseLibrary(GfxBase);
 
 if (screen)
    CloseScreen(screen);

 if (IntuitionBase)
    CloseLibrary(IntuitionBase); 

 exit(exitlevel);
}

/****************************************************************************/

struct InputEvent *myhandler(ev,mydata)

/* This input handler inserts itself at a higher priority than the intuition
   handler. It will intercept all raw-key events and put them into the ring-
   buffer so that other tasks in this program can use the data to keep track 
   of what keys have been pressed by the user ... */

struct InputEvent *ev;
struct MemEntry   *mydata[];

{ 
 register struct InputEvent *NextEvent, *LastEvent;

/*  look at all events in the event-list (or whatever it's called) and
    put in the buffer all raw-key events whose time stamp indicates
    we haven't looked at them before. Hopefully the system links new events
    at the end of the chain, so that all time stamps are in order. */

 NextEvent = ev;   /* First entry in event-list */
 LastEvent = NULL;
 do {
     if ((NextEvent->ie_Class == IECLASS_RAWKEY) &&
         (NextEvent->ie_Qualifier == LEFT_AMIGA))
        {

         /* Get our own copy of the event */
         movmem(NextEvent,&EventRing,sizeof(struct InputEvent));

         if (LastEvent == NULL)
            ev = NextEvent->ie_NextEvent;
         else
            LastEvent->ie_NextEvent = NextEvent->ie_NextEvent;
            
         /* Is the user of the buffer waiting ? */
         if (Waiting)
            {
            Signal(MainTask,1<<MainSignal);
            Waiting = 0;
            }
        }  
     else
        LastEvent = NextEvent;
     NextEvent = NextEvent->ie_NextEvent;
    }  /* do */
    while (NextEvent);    /* Done ? */

 return (ev);
} /* end of myhandler */

/****************************************************************************/

void Dial(Digit)
int Digit;
{ 
   int cont;
   
   if (Digit == 0)
      Digit = 10;
   for(cont = 0; cont < Digit; cont++)
   {
      /* DTR high (not active) */
      MODEM |= DTR;
      currentval.tv_secs = 0;
      currentval.tv_micro = 69000;
      TimeDelay(&currentval,UNIT_MICROHZ);
   
      /* DTR low (active) */
      MODEM ^= DTR;
      currentval.tv_secs = 0;
      currentval.tv_micro = 46000;
      TimeDelay(&currentval,UNIT_MICROHZ);
   }
   pause(1,0);
}

/****************************************************************************/

void pause(secs, micro)
int secs, micro;
{
   currentval.tv_secs = secs;
   currentval.tv_micro = micro;
   TimeDelay(&currentval,UNIT_MICROHZ);
}

/****************************************************************************/

struct timerequest *
CreateTimer(unit)
ULONG unit;
{
   int error;
   struct MsgPort *timerport;
   struct timerequest *timermsg;
     
   timerport = CreatePort(0, 0);
   if(timerport == NULL)
      return(NULL);
   timermsg = (struct timerequest *)
                      CreateExtIO(timerport,sizeof(struct timerequest));
   if(timermsg == NULL)
      return(NULL);
   error = OpenDevice(TIMERNAME, unit, timermsg, 0);
   if(error != 0)
      {
      DeleteTimer(timermsg);
      return(NULL);
      }
   return(timermsg);
}

/****************************************************************************/

TimeDelay(tv, unit)
struct timeval *tv;
int unit;
{
   struct timerequest *tr;
   tr = CreateTimer(unit);
   if(tr == NULL) return(-1);
   WaitForTimer(tr, tv);
   DeleteTimer(tr);
   return(0);
}

/****************************************************************************/

void WaitForTimer(tr, tv)
struct timerequest *tr;
struct timeval *tv;
{
   tr->tr_node.io_Command = TR_ADDREQUEST;
   tr->tr_time = *tv;
   DoIO(tr);
}

/****************************************************************************/

void DeleteTimer(tr)
struct timerequest *tr;
{
   struct MsgPort *tp;
     
   if(tr != 0)
   {
   tp = tr->tr_node.io_Message.mn_ReplyPort;
   if(tp != 0)
   DeletePort(tp);
   CloseDevice(tr);
   DeleteExtIO(tr, sizeof(struct timerequest));
   }
} /* end of DeleteTimer */

/****************************************************************************/

void DialNumber()
{
   int  cont, dum, oldtimeout, digit;

   oldtimeout = timeout;
   SetWindowTitles(window,"       Dialing...      ",-1);
   MODEM |= (DTR|RTS);  /* hangup (DTR & RTS high: not active) */
   pause(3,0);  /* pause 5 secs before start calling */

   if (check_abort()==TRUE)
      goto continuous2;
   MODEM ^= DTR;  /* on line! */
   pause(3,0);  /* pause 3 secs to take line properly */
   
   for(cont = 0; cont < strlen(SIBuffer1); cont++)
      {
      if (check_abort()==TRUE)
         goto continuous2;
      digit = (int)((SIBuffer1[cont])-48);
      if (digit >= 0 && digit <= 9)
         Dial(digit);
      if (digit >= -4 && digit <= -1)  /* valid pause characters: -/., */
         pause(5,0);
      }
   MODEM ^= RTS;
   if (timeout > 0)
      {
      SetWindowTitles(window,"Waiting Carrier Detect.",-1);
      for (; timeout >= 0; timeout--)
         {
         if (check_abort()==TRUE)
            goto continuous2;
         pause(1,0);
         sprintf(SIBuffer4,"%2d",timeout);
         RefreshGadgets(&Gadget4,window,NULL);
         if ((MODEM & (DSR|CTS|CD))==ACTIVE)
            {
            for (dum=0;dum<20;dum++)
               {
               pause(0,100000);
               if ((MODEM & (DSR|CTS|CD))==ACTIVE)
                  {                     /*12345678901234567890123*/
                  SetWindowTitles(window,"CD ok.   -Connected-   ",-1);
                  goto continuous2;
                  }
               } /* if modem active step2 */
            } /* if modem active */
         } /* timeout */
      SetWindowTitles(window,"No CD.  -Disconnected- ",-1);
      MODEM |= (DTR|RTS);   /*12345678901234567890123*/
      } /* if timeout>0 */
   else
      SetWindowTitles(window,"Done. -Not testing CD- ",-1);
   continuous2:
   Gadget2.Flags ^= SELECTED;
   RefreshGadgets(&Gadget2,window,NULL);
   sprintf(SIBuffer4,"%2d",oldtimeout);
} /* end of DialNumber */

/****************************************************************************/

check_abort()
{
   if (message = (struct IntuiMessage *)GetMsg(window->UserPort))
      {
      ReplyMsg(message);
      if (message->Class == GADGETDOWN)
         {
         SetWindowTitles(window,"Cancel requested: Abort",-1);
         MODEM |= (DTR|RTS);
         return(TRUE);
         }
      }
   return(FALSE);
} /* end of check_abort */

/****************************************************************************/

void show_go()
{
   int dum;
   
   for (dum = 16; dum > 0; dum--)
      {
      if (message = (struct IntuiMessage *)GetMsg(window->UserPort))
         {
         ReplyMsg(message);
         if (message->Class == GADGETDOWN)
            break;
         }
      pause(0,500000);
      }
} /* end of show_go */
