            /* Create xrb - xmodem_request_block */
/*lint -e544 (ignore stuff after #endif) */
                        /* a not so simple terminal program */
                                   /* Nik Conwell */
#define MAIN_MODULE 1

#include "term.h"                  /* Defines */
#include "term.data"               /* Data Seg for this prg */
#include "term.common"             /* Common segment */

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Z_Term *zt;

main()
{
 zt = (struct Z_Term *)
          AllocMem(sizeof(*zt),MEMF_PUBLIC|MEMF_CLEAR); 

 open_libraries();            /* Open up good libs */
 create_console(zt);          /* Create stuff for console */
 create_ser_device(zt);       /* Create stuff for modem */
 create_timer_device(zt);       /* Create stuff for sys timer */

/* set bit masks, so that we are awakened when these bits are set */

 zt->consolereadbit = zt->consolereadport->mp_SigBit;
 zt->w1_intuitionmsgbit = zt->w1->UserPort->mp_SigBit;
 zt->serialipbit = zt->read_request->IOSer.io_Message.mn_ReplyPort->mp_SigBit;

/* Do misc inits */
 zt->prev_alg = 0;
 zt->prev_baud = 0;
 zt->prev_blocksize = 0;
  

 con_put_str("Amiga Terminal Active.\n",zt);

 do
 {
  zt->wakeupmask = Wait(W1_INTUITION_MESSAGE |
                    TYPED_CHARACTER |
                    SERIAL_INPUT);

/* The console (read) woke us up */

 if (zt->wakeupmask & TYPED_CHARACTER)
    {
     GetMsg(zt->consolereadport);
     zt->rs_out = zt->iletter;
     DoIO(zt->write_request);
/* put code for echo here */
     queue_read(zt);
    }

/* Input from the serial port woke us up. */

 if (zt->wakeupmask & SERIAL_INPUT)
    {
     WaitIO(zt->read_request);
     zt->oletter = zt->rs_in & 0x7f;
     BeginIO(zt->read_request);
     con_put_char(zt->oletter,zt);
     if (zt->rf == 1)    /* have the receive file switch on ?? */
        {
         zt->st = write(zt->f1,&(zt->oletter),1);
        }
    }  /* end if */


/* Intuition woke us up on window 1. */

  if (zt->wakeupmask & W1_INTUITION_MESSAGE)
    {
       while ((zt->message = (struct IntuiMessage *)
               GetMsg(zt->w1->UserPort)) != NULL)
          {
           handle_intui_message(zt);
           if ((zt->class == MENUPICK) && (zt->code != MENUNULL))
              {
               handle_menu(zt);
              }  /* end if class == valid menupick */
          }  /* end while there is something on w1's port */
    }  /* end if wakeupmask says intuition woke us up */

 } while (zt->class != CLOSEWINDOW);  /* end do while */
 

  /* do the closing cleanup crap */
 getout(FAIL_NO_FAIL,zt);

}

/* some functions that we need */

void queue_read(zt)
    struct Z_Term *zt;
    {
     zt->consolereadmsg->io_Command = CMD_READ;
     zt->consolereadmsg->io_Data = (APTR) &(zt->iletter);
     zt->consolereadmsg->io_Length = 1;
     SendIO(zt->consolereadmsg);
    }  /* end queue_read(zt) */

void con_put_char(character,zt)
     char character;
     struct Z_Term *zt;
    {
     zt->consolewritemsg->io_Command = CMD_WRITE;
     zt->consolewritemsg->io_Data = (APTR) &character;
     zt->consolewritemsg->io_Length = 1;
     DoIO(zt->consolewritemsg);
    }  /* end con_put_char */





void con_put_str(string,zt)
    char *string;
    struct Z_Term *zt;
   {
    zt->consolewritemsg->io_Command = CMD_WRITE;
    zt->consolewritemsg->io_Data = (APTR) string;
    zt->consolewritemsg->io_Length = -1;
    DoIO(zt->consolewritemsg);
   }  /* end con_put_str() */





/* Copy needed fields from intui_message, then reply immediately */

void handle_intui_message(zt)

struct Z_Term *zt;

{
 zt->class = zt->message->Class;
 zt->code = zt->message->Code;
 zt->qualifier = zt->message->Qualifier;
 zt->address = zt->message->IAddress;
 ReplyMsg(zt->message);
}  /* end handle_intui_message(zt) */







/* Handle processing for menu items selected */

void handle_menu(zt)

struct Z_Term *zt;

{
 zt->menunum = MENUNUM(zt->code);
 zt->menuitem = ITEMNUM(zt->code);
 switch(zt->menunum)
  {
   case MENU_PROJECT  : switch(zt->menuitem)
             {
              case MENU_PROJECT_INFO : 
                       AutoRequest(zt->w1,
		                   &AboutText[0],
				   NULL,
				   &OKText,0,0,315,100);
                       break;
              case MENU_PROJECT_QUIT :
                       zt->class = CLOSEWINDOW;
                       break;
             }
            break;
   case MENU_BAUD : handle_baud(zt);
                    break;
   case MENU_FILESTUFF  : switch(zt->menuitem)
             {
              case MENU_FILESTUFF_SEND_XMODEM :
         	       getfilename(zt->filename); 
                       if (zt->filename[0] == NULL)
                          {
                           break;
                          }
                       xmodem_send_file(zt);
                       break;
              case MENU_FILESTUFF_READ_XMODEM :
                       getfilename(zt->filename);
                       if (zt->filename[0] == NULL)
                          {
                           break;
                          }  
                       xmodem_read_file(zt);
                       break;
              case MENU_FILESTUFF_RECEIVE_TEXT :
                       getfilename(zt->filename);
                       if (zt->filename[0] == NULL)
                          {
                           break;
                          }
                       if ((zt->f1 = creat(zt->filename,NULL)) < NULL)
                          {
                           con_put_str("\nCannot open rcv file - Exists.\n",zt);
                          }
                       else
                          {
                           zt->rf = 1;                   
                          }
                       break;
              case MENU_FILESTUFF_RECEIVE_TEXT_END : 
                       if (zt->rf == 1)
                         {
                          zt->rf = 0;
                          close(zt->f1);
                          break;
                         }
              case MENU_FILESTUFF_SEND_TEXT : 
                       getfilename(zt->filename);
                       if (zt->filename[0] == 0)
                          {
                           break;
                          }
                       type(zt);
                       break;
            }  /* end switch (menuitem) */
			break;
   case MENU_XMODEM_OPTIONS : set_xmodem_options(zt);
   			      break;

  }  /* end of menunum switch */
}  /* end of handle_menu() */






void type(zt)
struct Z_Term *zt;

{
char ch;    /* character read from the file */

  if ((zt->f2 = fopen(zt->filename,"r")) == NULL)
     {
      con_put_str("\nCannot open send file. - Not found.\n");
     }  /* end if the file open was not ok */
  else
     {
      while ((ch = getc(zt->f2)) != EOF)
       {
        sendchar((char) ch,zt);
        if ((zt->message = (struct IntuiMessage *)
             GetMsg(zt->w1->UserPort)) != NULL)
          {
           handle_intui_message(zt);
           if ((zt->class == MENUPICK) && (zt->code != MENUNULL))
             {
              zt->menunum = MENUNUM(zt->code);
              zt->menuitem = ITEMNUM(zt->code);
              if ((zt->menunum == MENU_FILESTUFF) && 
                  (zt->menuitem == MENU_FILESTUFF_ABORT_XMODEM))
               {
                con_put_str("\nUser Cancelled Text Send.\n",zt);
                break;   /* break out of the while loop */
               }  /* end if we have the correct menu item */
             }  /* end if the message signifies menu playness */
          }  /* end if there something on the message port */
       }  /* end while there is another char to send */
      if ((zt->st = fclose(zt->f2)) == -1)
         {
          con_put_str("\nCouldn't close send file.\n",zt);
         }  /* end if close was not ok */      
     }  /* end else (if file open was ok) */
}  /* end type() */






/* Change the baud rate specified */

void handle_baud(zt)

struct Z_Term *zt;

{
 char baud_notify[80];
 char baud_alpha[BAUD_ALPHA_LEN];
 switch(zt->menuitem)
   {
    case 0 : zt->baud=110;
             break;
    case 1 : zt->baud=300;
             break;
    case 2 : zt->baud=1200;
             break;
    case 3 : zt->baud=2400;
             break;
    case 4 : zt->baud=4800;
             break;
    case 5 : zt->baud=9600;
             break;
    case 6 : zt->baud=19200;
             break;
    case 7 : zt->baud=31250;
             break;
             }

  strcpy(baud_notify,"\nBaud changed to ");
  stci_d(baud_alpha,zt->baud,BAUD_ALPHA_LEN);
  strcat(baud_notify,baud_alpha);
  strcat(baud_notify,"\n");
  con_put_str(baud_notify,zt);

  remove_ser_1(zt);       /* remove 1'st part of ser device */
  remove_ser_2(zt);       /* remove 2'nd part of ser device */
  create_ser_device(zt);  /* recreate the dev again */
  fix_menu(zt);
}  /* End handle_baud(zt) */

void open_libraries()

/* Open up system libraries  (Dos already opened) */
{

 IntuitionBase = (struct IntuitionBase *)
                 OpenLibrary("intuition.library",INTUITION_REV);

 if (IntuitionBase == NULL)
    {
#ifdef DEBUG
     printf("Cannot open Intuition.\n");
#endif
     getout(FAIL_INTUITION_OPEN,zt);
    }
 GfxBase = (struct GfxBase *) 
           OpenLibrary("graphics.library",GRAPHICS_REV);
 if (GfxBase == NULL)
    {
#ifdef DEBUG
     printf("Cannot open graphics library.\n");
#endif
     getout(FAIL_GRAPHICS_OPEN,zt);
    }
}

void create_console(zt)

struct Z_Term *zt;

/* Create a path to the user */
{
 zt->w1 = (struct Window *) OpenWindow(&NewWindowStructure);
 if (zt->w1 == NULL)
    {
#ifdef DEBUG
     gripe("Cannot open window.","","");
#endif
     getout(FAIL_W1_WINDOW_OPEN,zt);
    }

/* Set up the Menu */

 SetMenuStrip(zt->w1,(struct Menu *) &MenuList);

 zt->consolewriteport = (struct MsgPort *) 
                    CreatePort("term.con.write.port",NULL);
 if (zt->consolewriteport == NULL)
    {
#ifdef DEBUG
     gripe("Cannot open console write port.","","");
#endif
     getout(FAIL_CONSOLEWRITEPORT_OPEN,zt);
    }
 zt->consolewritemsg = (struct IOStdReq *) 
                       CreateStdIO(zt->consolewriteport);
 if (zt->consolewritemsg == NULL)
    {
#ifdef DEBUG
     gripe("Cannot open write path.","","");
#endif
     getout(FAIL_CONSOLEWRITESTDIO_OPEN,zt);
    }
 zt->consolereadport = (struct MsgPort *)
                       CreatePort("term.con.read.port",NULL);
 if (zt->consolereadport == 0)
    {
#ifdef DEBUG
     gripe("Cannot open console read port.","","");
#endif
     getout(FAIL_CONSOLEREADPORT_OPEN,zt);
    }

 zt->consolereadmsg = (struct IOStdReq *) 
                      CreateStdIO(zt->consolereadport);
 if (zt->consolereadmsg == 0)
    {
#ifdef DEBUG
     gripe("Cannot open console read path.","","");
#endif
     getout(FAIL_CONSOLEREADSTDIO_OPEN,zt);
    }

 zt->consolewritemsg->io_Data = (APTR) zt->w1;
 zt->consolewritemsg->io_Length = sizeof(*(zt->w1));

 if (OpenDevice("console.device",NULL,zt->consolewritemsg,NULL))
   {
#ifdef DEBUG
     gripe("Couldn't open up console total.\n");
#endif
     getout(FAIL_CONSOLE_OPEN,zt);
   }

 zt->consolereadmsg->io_Device = zt->consolewritemsg->io_Device;
 zt->consolereadmsg->io_Unit = zt->consolewritemsg->io_Unit;
 queue_read(zt);

}  /* end create_console() */





void create_ser_device(zt)

struct Z_Term *zt;

/* Create path to the modem */
{
zt->read_request = (struct IOExtSer *)
                 AllocMem(sizeof(*(zt->read_request)),MEMF_PUBLIC|MEMF_CLEAR);
zt->read_request->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
zt->read_request->IOSer.io_Message.mn_ReplyPort = (struct MsgPort *)
                  CreatePort("term.ser.read.port",NULL);

 if (OpenDevice(SERIALNAME,NULL,zt->read_request,NULL))
   {
#ifdef DEBUG
    gripe("Failed to open read serial.device.","","");
#endif
    getout(FAIL_SERIAL_READ_OPEN,zt);
   }  /* end if */

 zt->write_request = (struct IOExtSer *)
                 AllocMem(sizeof(*(zt->write_request)),MEMF_PUBLIC|MEMF_CLEAR);
 zt->write_request -> io_SerFlags = SERF_SHARED|SERF_XDISABLED;
 zt->write_request -> IOSer.io_Message.mn_ReplyPort = (struct MsgPort *)
                  CreatePort("term.ser.write.port",NULL);

 if (OpenDevice(SERIALNAME,NULL,zt->write_request,NULL))
    {
#ifdef DEBUG
     gripe("Failed to open write serial.device.");
#endif
     getout(FAIL_SERIAL_WRITE_OPEN,zt);
    }  /* end if */

 zt->write_request->IOSer.io_Command = CMD_WRITE;
 zt->write_request->IOSer.io_Length = 1;
 zt->write_request->IOSer.io_Data = (APTR) &(zt->rs_out);

 zt->read_request->io_SerFlags = SERF_SHARED|SERF_XDISABLED;
 zt->read_request->io_Baud = zt->baud;
 zt->read_request->io_ReadLen = 8;
 zt->read_request->io_WriteLen = 8;
 zt->read_request->io_CtlChar = 1L;
 zt->read_request->IOSer.io_Command = SDCMD_SETPARAMS;
 DoIO(zt->read_request);

 zt->read_request->IOSer.io_Command = CMD_READ;
 zt->read_request->IOSer.io_Length = 1;
 zt->read_request->IOSer.io_Data = (APTR) &(zt->rs_in);
 BeginIO(zt->read_request);
}  /* end create_ser_device(zt) */




/* Create the interface to the system timer */

void create_timer_device(zt)

struct Z_Term *zt;

{
 if ((zt->timerport = (struct MsgPort *) 
                      CreatePort(NULL,NULL)) == NULL)
   {
#ifdef DEBUG
    gripe("Could not create timer port.","","");
#endif
    getout(FAIL_TIMER_CREATE_PORT,zt);
   }
 if ((zt->timermsg = (struct IOStdReq *) 
                     CreateStdIO(zt->timerport)) == NULL)
   {
#ifdef DEBUG
    gripe("Could not open timer stdio.","","");
#endif
    getout(FAIL_TIMER_CREATE_STDIO,zt);
   }
 if (OpenDevice(TIMERNAME,UNIT_VBLANK,zt->timermsg,0) != NULL)
   {
#ifdef DEBUG
    gripe("Could not open timer device.","","");
#endif
    getout(FAIL_TIMER_OPEN_DEVICE,zt);
   }
}  /* end create_timer_device */





void getout(fail_code,zt)

/* Process exit program requests */

int fail_code;
struct Z_Term *zt;

{
 if (fail_code > FAIL_TIMER_OPEN_DEVICE)
  {
   AbortIO(zt->timermsg);
   CloseDevice(zt->timermsg);
  }
 if (fail_code > FAIL_TIMER_CREATE_STDIO)
  {
   DeleteStdIO(zt->timermsg);
  }
 if (fail_code > FAIL_TIMER_CREATE_PORT)
  {
   DeletePort(zt->timerport);
  }
 if (fail_code > FAIL_SERIAL_WRITE_OPEN)
  {
   remove_ser_1(zt);
  }
 if (fail_code > FAIL_SERIAL_READ_OPEN)
   {
    remove_ser_2(zt);
    CloseDevice(zt->consolewritemsg);
   }
 if (fail_code > FAIL_CONSOLE_OPEN)
   {
    ClearMenuStrip(zt->w1);
    DeleteStdIO(zt->consolereadmsg);
   }
 if (fail_code > FAIL_CONSOLEREADSTDIO_OPEN)
   {
    DeletePort(zt->consolereadport);
   }
 if (fail_code > FAIL_CONSOLEREADPORT_OPEN)
   {
    DeleteStdIO(zt->consolewritemsg);
   }
 if (fail_code > FAIL_CONSOLEWRITESTDIO_OPEN)
   {
    DeletePort(zt->consolewriteport);
   }
 if (fail_code > FAIL_CONSOLEWRITEPORT_OPEN)
   {    
    CloseWindow(zt->w1);
   }
 if (fail_code > FAIL_W1_WINDOW_OPEN)
   {
    CloseLibrary(GfxBase);
   }
 if (fail_code > FAIL_GRAPHICS_OPEN)
   {
    CloseLibrary(IntuitionBase);
   }
 FreeMem(zt,sizeof(*zt));
 exit(fail_code);
}

void remove_ser_1(zt)

struct Z_Term *zt;

/* remove serial device - part 1 */
{
 AbortIO(zt->read_request);
 AbortIO(zt->write_request);
 CloseDevice(zt->read_request);
 CloseDevice(zt->write_request);
 DeletePort(zt->write_request->IOSer.io_Message.mn_ReplyPort);
 FreeMem(zt->write_request,sizeof(*(zt->write_request)));
}  /* end remove_ser_1(zt) */

 

void remove_ser_2(zt)

struct Z_Term *zt;

/* remove serial device - part 2 */

{
 DeletePort(zt->read_request->IOSer.io_Message.mn_ReplyPort);
 FreeMem(zt->read_request,sizeof(*(zt->read_request)));
}  /* End remove_ser_2() */




void set_timer(time_wait,zt)

/* Tell system to return this msg to us when the time is up */

int time_wait;
struct Z_Term *zt;

{
 AbortIO(zt->timermsg);                         /* Trash outstandings */
 zt->timermsg->io_Command = TR_ADDREQUEST;
 zt->timermsg->io_Actual = time_wait;           /* Wait n seconds */
 zt->timermsg->io_Length = 0;
 SendIO(zt->timermsg);
}  /* End set_timer() */

void set_xmodem_options(zt)

struct Z_Term *zt;

{
 switch (zt->menuitem)
  {
   case MENU_XMODEM_OPTIONS_128_BLOCK	
		:	zt->xfer_blocksize = XMODEM_128_BLOCK;
			con_put_str("\nXfer Blocksize set at 128 bytes.\n",zt);
			break;
   case MENU_XMODEM_OPTIONS_1024_BLOCK	
		:	zt->xfer_blocksize = XMODEM_1024_BLOCK;
			con_put_str("\nXfer Blocksize set at 1024 bytes.\n",zt);
   			break;
   case MENU_XMODEM_OPTIONS_CHECKSUM	
		:	zt->xfer_error_detect_alg = XMODEM_CHECKSUM;
			con_put_str("\nXfer error detect alg set to Checksum.\n",zt);
   			break;
   case MENU_XMODEM_OPTIONS_CRC16	
		:	zt->xfer_error_detect_alg = XMODEM_CRC16;
			con_put_str("\nXfer error detect alg set to CRC-16.\n",zt);
   			break;
  }

 fix_menu(zt);
}  /* end set_xmodem_options */





/* Redo checked portions of the menu strip */

fix_menu(zt)


struct Z_Term *zt;

{
 ClearMenuStrip(zt->w1);

/* Uncheck previous selection menu items */
/* This selection will be checked by Intuition */
 if (zt->prev_baud != zt->baud)
  {
   switch(zt->prev_baud)
    {
     case 110:   MenuItem12.Flags &= ~CHECKED;
                 break;
     case 300:   MenuItem13.Flags &= ~CHECKED;
                 break;
     case 1200:  MenuItem14.Flags &= ~CHECKED;
                 break;
     case 2400:  MenuItem15.Flags &= ~CHECKED;
                 break;
     case 4800:  MenuItem16.Flags &= ~CHECKED;
                 break;
     case 9600:  MenuItem17.Flags &= ~CHECKED;
                 break;
     case 19200: MenuItem18.Flags &= ~CHECKED;  
                 break;
     case 31250: MenuItem19.Flags &= ~CHECKED;
    }
   zt->prev_baud = zt->baud;
  }

 if (zt->prev_alg != zt->xfer_error_detect_alg)
  {
   if (zt->prev_alg == XMODEM_CRC16)
      MenuItem4.Flags &= ~CHECKED;

   if (zt->prev_alg == XMODEM_CHECKSUM)
      MenuItem3.Flags &= ~CHECKED;
   zt->prev_alg = zt->xfer_error_detect_alg;
  }

 if (zt->prev_blocksize != zt->xfer_blocksize)
  {
   if (zt->prev_blocksize == XMODEM_1024_BLOCK)
      MenuItem2.Flags &= ~CHECKED;

   if (zt->prev_blocksize == XMODEM_128_BLOCK)
      MenuItem1.Flags &= ~CHECKED;
   zt->prev_blocksize = zt->xfer_blocksize;
  }

 SetMenuStrip(zt->w1,(struct Menu *) &MenuList);
}  /* End fix_menu() */
