/*    Comm 1.34 -- The Communicator -- a terminal program for Amiga */

/*
         This program is placed in the public domain is freely
         distributable and is intended for personal use only.
         Sale of this program except for REASONABLE media costs
         is prohibited.
*/

#define  COMM 1
#define  RXCRLF  0xFF00
#define  TXCRLF  0x00FF

#include "globals.h"
#include <fcntl.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <workbench/icon.h>

#define CREATE  O_WRONLY | O_CREAT | O_TRUNC

extern USHORT Read_RS();
extern int    init_serial(), Open_Timer(), Close_Timer(), Split_Window(),
              MyCloseWindow();
extern UBYTE  toasc(), *get_phnum(), *malloc(), *MyOpenWindow(),
              *OpenLibrary();
extern void   dial(), Init_phone_lib(), list_plib(), Single_Window(), InitMenu(),
              emit_tx(), emits_tx(), emit_rx(), emits_rx(), InitReq(),
              hang_up();
extern struct MenuItem *ItemAddress();
extern struct IntuiMessage *GetMsg();
extern struct Window *OpenWindow();
extern struct Screen *OpenScreen();
extern struct Task   *FindTask();

int    KeepGoing, capture, send, ph_nums, menu_event, tranr, bcount, gotxon,
       close_view = FALSE, scrnpos = 13, prefbaud;
char   name[MAXFNAME],  strbuff[ MAXFNAME + 41 ], *number, c;
FILE   *trans;
ULONG  sdelay = 0, IconBase = 0;


static int  lcnt = 0;      /* ascii debug character counter */
static char line[17];      /* ascii debug line buffer */
static APTR err_window;

static int timeron= FALSE; /* true if timer device opened */
USHORT tmpchopflg = FALSE; /* hold state of chopflg during XMODEM recv. */
USHORT eolflg     = 0;

#define C_OFF 0
#define C_ON  1
#define C_SUS 2
UBYTE  *stat[] = {(UBYTE *)"   ",(UBYTE *)"ON ",(UBYTE *)"SUS"};
struct View          *View          = NULL;
struct ViewPort      *ViewPort      = NULL, *ViewPortAddress();

/******************************************************/
/*                   Main Program                     */
/*                                                    */
/*      This is the main body of the program.         */
/******************************************************/

main(argc,argv)
int argc;
char **argv;
{
  void   help(), decode_raw_key(), Process_tx_event(), Process_rx_event();
  void   Process_rq_event(), Process_vw_event(), InitSystem(), Process_menu_event();
  void   Process_screen_item(), Process_baud_rate();

  SetTaskPri(FindTask(0L),install.priority);/* bump our priority a little */

  InitSystem(argc,argv);            /* Open windows and devices */
  InitMenus();                      /* init. menus */
  Init_phone_lib();                 /* initialize phone library  */
  SetMenuStrip(tx_window,menu);     /* attach menus to tx window */

  KeepGoing = gotxon = TRUE;
  close_window = send = capture = FALSE;
  trans = NULL; tranr = NULL;
  DeActivate(&Dirgadget);

  ph_nums = load_plib(phonedir);    /* load the phone library */

  if(Init_keymacros()==NULL)        /* and the key macro file */
  {
      sprintf(sbuff,"Can't open key file %s\n",commkeys);
      emits_rx(sbuff);
  }
  menu_event = NULL;                /* no menu items selected */
  BeginIO(Read_Request);            /* ready serial input */
  if(install.prefbaud)
    Process_baud_rate( prefbaud );  /* adjust baud rate */
  Modem_init();                     /* send init string to modem */
  Xon(xonflg);                      /* enable XON/XOFF protocol if selected */
  *name = NULL;
  capt_status = stat[ C_OFF ];

  while( KeepGoing )                /* the big loop */
  {
     if (send && gotxon)            /* if we are in ASCII send mode and enabled */
     {
         if ((c = getc(trans)) != EOF)      /* get a byte from the file */
         {
             Delay(sdelay);                 /* slider delay */
             if( c == '\n')
                 OutChar('\r');             /* if LF, send CR */
             else if( c != '\r') OutChar(c);
         }
         else
         {
            fclose(trans);                /* here at end of file */
            emits_rx("\nFile Sent\n");
            send = FALSE;                 /* turn off send flag */
            Swap_capture(ASCSEND,START);  /* normal menu entry */
          }
     }
     else
   /* wait for requester, serial port or other windows message */

     Wait((1L << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit)
        | (1L << tx_window->UserPort->mp_SigBit));

     Process_window_event();
     while(CheckIO(Read_Request))     /* any serial activity? */
     {
         Process_serial_chars();
         BeginIO(Read_Request);
         Process_window_event();
     }
  }  /* end while ( keepgoing ) */

/*   It must be time to quit, so we have to clean
*   up and exit.
*/
   if(capture)
   {
      flush();                /* flush capture buffer */
      close(tranr);
   }
   if(prt)
      close(prt);             /* release printer */

   clean_up(0L);              /* shut everything down */
   exit( 1 );
} /* end of main */

/*************************************************************
   Get and process characters from the serial device.  Characters are found
   in array rs_in.  Serlen contains the number of characters in the buffer.
*/
Process_serial_chars()
{
   USHORT bfcnt, i, serlen;
   UBYTE  dispbuf[ RSBUFSIZ * 2 ];

   serlen = Read_RS();
   for(bfcnt = i = 0; i < serlen; i++)
   {
     if(rs_in[i] == NULL) continue;

     if(debug & NOMASK)       /* strip parity? */
       c = rs_in[i];          /* no */
     else
       c = rs_in[i] & 0x7f;   /* yes */

       if (capture && capton)       /* capturing data to disk file? */
         if (isprint(c)) buffer_it(c);
         else
            switch(c)      /* only allow some control chars in file */
            {
               case '\n':
/*             case '\r':     */
               case '\t':
                          buffer_it(c);
            }
       if(debug & SHOWHEX)       /* Show HEX character? */
       {
         sprintf(sbuff,"%02.2x ",c);    /* print HEX digit pair */
         emits_rx(sbuff);

         line[lcnt++] = (isprint(c) ? c : '.'); /* buffer ASCII */
         if(lcnt > 16)                  /* until 16 HEX chars */
         {
           line[lcnt] = NULL;
           emits_rx("   ");  /* dump ASCII debug buffer */
           emits_rx(line);
           emit_rx('\n');
           lcnt = 0;
         }
       }
       else                /* not showing HEX characters */
         switch (c)        /* filter out control chars. */
         {
           case XON:
                     gotxon = TRUE;  break;
           case XOFF:
                     gotxon = FALSE; break;
           case 7:        /* except BELL   */
                    Beep(); break;
           case '\r':     /*   "    CR     */
                      if(eolflg & RXCRLF)
                      {
                           c = '\n';
                           dispbuf[bfcnt++] = '\r';
                      }
           case 8:        /*   BACKSPACE   */
           case 9:        /*   "    TAB    */
           case '\n':     /*   " NEWLINE   */
           case '\f':     /*   " FORM FEED */
           case 0x1b:     /*   "    ESC    */
                    dispbuf[bfcnt++] = c;
                    break;
           default:   if(isprint(c))
                        dispbuf[bfcnt++] = c;
                      break;
        }
    }
    dispbuf[bfcnt] = NULL;         /* end buffer with a NULL */
    if((debug & SHOWHEX) == 0)
       emits_rx(dispbuf);          /* print string to screen */

    doprint(dispbuf,bfcnt);        /* and to printer (if on) */
}

/* print a string on the printer */
doprint(addr,cnt)
UBYTE *addr;
int   cnt;
{
   UBYTE *buff;
   int   tmp;

   if(printon != TRUE)           /* if not selected, return */
      return;

   buff = addr;
   tmp = cnt;

   while(tmp--)
   {
     if(*addr == 8)              /* BACKSPACE? */
        *addr = 0x7F;            /* make it DELETE */
     if(isprintable(*addr))
     {
        addr++;
        continue;
     }
     else
        *addr++ = NULL;          /* zap out unprintable characters */
     }

     if(write(prt,buff,cnt) != cnt)
     {
         printon = FALSE;
         close(prt);  Beep();
         emits_rx("\n\nERROR writing to printer -- print aborted\n");
     }
}

/* determine what is and isn't printable on the printer */
isprintable(ch)
UBYTE ch;
{
   ch &= 0x7F;

   if(isprint(ch))         /* I allow all alphanumerics */
      return TRUE;
   switch(ch)              /* and these control characters */
   {
      case 10: case 13: case 9: case 7: case 8: case 0x7F:
               return TRUE;
   }
   return FALSE;
}

/* an IDCMP port message has been received.  Determine the window it
    came from then process the message
*/
Process_window_event()
{
  while( NewMessage = GetMsg(tx_window->UserPort) )
     Process_window_msg( NewMessage );
}

Process_window_msg(msg)
struct IntuiMessage *msg;
{
  ULONG  class;
  USHORT code,      qual;
  APTR   address;
  struct Window   *which;           /* which window has an event */

    
  class   = msg->Class;
  code    = msg->Code;
  qual    = msg->Qualifier;
  which   = msg->IDCMPWindow;
  address = msg->IAddress;
  ReplyMsg( msg );

  if(class == RAWKEY || class == MENUPICK)
      Process_tx_event( (long)class, code, qual, address);
  else if(which == tx_window)
      Process_tx_event( (long)class, code, qual, address);
  else if(which == vw_window)
      Process_vw_event( (long)class, code, qual);
  else if(which == req_window)
      Process_rq_event( (long)class, address);
  else if(which == rx_window)
      Process_rx_event( (long)class, code, qual, address);
  else if(which == st_window)
      {
         if(address == &delay_prop)
            sdelay = ((ULONG)propinfo.HorizPot >> 12);
         else
         {
            while( msg = GetMsg(st_window->UserPort) )  ReplyMsg(msg);
            ClearMenuStrip(st_window);
            MyCloseWindow(st_window);
            st_window = NULL;
         }
      }
  if(close_window)
  {
    Single_Window();
    SysItems[0].Flags &= ~CHECKED; /* turn off check mark in menu */
  }
  if(close_view)
  {
    if((close_view = MyCloseWindow(vw_window)) == FALSE)
       vw_window = NULL;
  }
}
/************************************************************************
   Some event happened in the rx window.  Process only the events we are
   interested in.
*/
void Process_rx_event( class, code, qual, address)
ULONG  class;
USHORT code, qual;
APTR   address;
{
     Process_tx_event( class, code, qual, address);
}


/**************************************************************************
   Some event happened in the tx window.  Process events we are interested
   in.
*/
void Process_tx_event( class, code, qual, address )
ULONG  class;
USHORT code, qual;
APTR   address;
{
  USHORT itemnum, menunum, subnum;
  struct MenuItem *Item;
  void   Process_menu_item();

  if(address == &tx_window_close)
      KeepGoing = FALSE;
  else if(address == &tx_window_front)
       {
          if(vw_window)
             WindowToFront(vw_window);
       }
  else if(address == &tx_window_back)
      ScreenToBack(commscreen);
  else if(address == &rx_window_close)
      close_window = TRUE;
  else if(address == &rx_window_front)
       {
         WindowToBack(tx_window);
         WindowToBack(rx_window);
       }
  else if(address == &rx_window_back)
      ScreenToBack(commscreen);
  else
  switch( class )
   {
     case CLOSEWINDOW:
/*
     User is ready to quit, so indicate that execution should terminate
     with next iteration of the loop.
*/
          KeepGoing = FALSE;
          break;

     case RAWKEY:
   /*  User has touched the keyboard */
          switch( code )
            {
               case 69: /* escape key */
                        abort = TRUE;
               default:
                     c = toasc(code,qual); /* get in into ascii */
                     decode_raw_key( c );
                     break;
            }
          break;

     case MENUPICK:
   /* we had a menu selection. */
                   while ( code != MENUNULL )
                   {
                      menunum = MENUNUM( code );
                      itemnum = ITEMNUM( code );
                      subnum  = SUBNUM(  code );
                      Process_menu_item( menunum, itemnum , subnum);
                      Item = ItemAddress( &menu[0], (long)code );
                      code = Item->NextSelect;
                   }
                   break;
   }   /* end of switch (class) */
}
/*
   View window was closed
*/
void Process_vw_event( class, code, qual )
ULONG  class;
USHORT code, qual;
{
     if( class == CLOSEWINDOW)
     {
         viewflg = FALSE;
         SysItems[1].Flags &= ~CHECKED;
         close_view = TRUE;
     }
}

/*
   Return was hit on string gadget
*/
void Process_rq_event( class, address )
ULONG  class;
APTR   address;
{
   struct IntuiMessage *msg;
   UBYTE ch;
/*
   User just hit return in the string input requester.  menu_event was
   set by process_tx_event() when the user selected the file transfer
   type.  Now we have the filename he entered, so go do the file xfer.
*/
   if(address == &Dirgadget)
   {
      ch = install.def_dir[ strlen(install.def_dir) -1 ];
      if(ch != ':' && ch != '/')
         strcat(install.def_dir,"/");
      if(dos_version == DOS12)
         ActivateGadget(&Strgadget,req_window,0L);
      return;
   }
   while( msg = GetMsg(req_window->UserPort) )  ReplyMsg(msg);

#ifdef ORIGINALCODE	/* Following code is bogus (fnf) */
   req_window = (struct Window *)MyCloseWindow(req_window);
#else
   (void) MyCloseWindow(req_window);
   req_window = NULL;
#endif
   if( (address == &Strgadget) || (address == &OKgadget) )
      Process_menu_event( menu_event );
   else menu_event = NULL;
}

/**************************************************************************
   User hit HELP key, print any helpful information.
*/
void help()
{
  int i;

  for(i = 0; i < KEYMACS; i++)
   if(keymacro[i])
    {
      sprintf(sbuff,"\n%c%d: ",(i > 9) ? 'S' : 'F',(i > 9) ? i-9 : i + 1);
      emits_rx(sbuff);
      emits_rx(keymacro[i]);
    }
  emit_rx('\n');
}

/*************************************************************************
      Decode and act upon any special function keys here.  Default action
      is to send the key out the serial port.
*/
void decode_raw_key( c )
char c;
{
   char  ch;

   switch(c & 0xff)        /* c should be unsigned */
   {
      case NULL:  break;
      case FN1: case FN2: case FN3: case FN4: case FN5:
      case FN6: case FN7: case FN8: case FN9: case F10:
      case SF1: case SF2: case SF3: case SF4: case SF5:
      case SF6: case SF7: case SF8: case SF9: case S10:
                 expand_macro( c );
                 break;

      case SHH:  help();          /* and list macros */
                 break;
      case HLP:  if(st_window)
                 {
                    ClearMenuStrip(st_window);
                    MyCloseWindow(st_window);
                    st_window = NULL;
                 }
                 else
                    Show_Status();   /* show status */
                 break;

      case XON:  Start_line();   gotxon = TRUE;
                 break;

      case TOGSCR:
                 MoveScreen(commscreen,0L,(long)scrnpos);
                 scrnpos *= -1;
                 break;
      case TOGCAP:
                 if(capture)             /* if its on, turn it off */
                 {
                    capton = !capton;
                    if(capton)
                       capt_status = stat[C_ON];
                    else
                       capt_status = stat[C_SUS];
                    status_line(75,capt_status);
                  }
                  else            /* open default file */
                  {
                     if((tranr = open(install.cap_name,CREATE)) == ERROR)
                     {
                        sprintf(sbuff,"\007\nERROR opening %s\n",install.cap_name);
                        emits_rx(sbuff);
                     }
                     else
                     {
                        capton = capture = TRUE;
                        bcount = 0;
                        Swap_capture(ASCCAPT,capture != TRUE);
                        sprintf(sbuff,"\007\nDefault CAPTURE file %s opened\n",install.cap_name);
                        emits_rx(sbuff);
                        capt_status = stat[C_ON];
                        status_line(75,capt_status);
                     }
                  }
                  RefreshStatus();
                  break;

        case TOGPRT:
                     if(printon)            /* if printer was on */
                     {
                        ch = 13;
                        doprint(&ch,1);     /* print a CR to clear buffer */
                        close(prt);
                        printon = FALSE;
                        prt = NULL;
                     }
                     else
                     {
                        if((prt = open("PRT:",O_WRONLY)) == -1)
                        {
                           Beep();
                           emits_rx("\n\nERROR opening printer\n");
                           break;
                        }
                        printon = TRUE;
                     }
                     RefreshStatus();
                     break;
/* wasn't a special key, so send it out the serial port */
        default:
                   OutChar(c);
     }
}

/* send a character out to the modem.  Process \r and \n here
*/
OutChar(ch)
UBYTE ch;
{
   rs_out[0] = ch;
   DoIO(Write_Request);
   if( ch == '\r' )
   {
      if( eolflg & TXCRLF )
         OutChar('\n');
   }
   if(halfduplex & !split_screen)
      emit_rx(ch);
   if(split_screen)
   {
      if(ch == '\r')     /* make CR into LF for */
        emit_tx('\n');  /* readability & scrolling */
      else if(ch == 8)
         emits_tx("\010 \010");  /* destructive BACKSPACE */
      else  if(ch == 7)
               Beep();
      else  emit_tx(ch);
   }
}

/**************************************************************************
   Process user selected menu item.  menuitem and itemnum were determined
   by process_tx_event()
*/
void Process_menu_item( menunum, itemnum, subnum)
USHORT   menunum, itemnum, subnum;
{
  void Process_file_item(), Process_baud_rate(), Process_sys_item();
  void Process_serial_item();

  switch( menunum )
    {
       case 0: Process_file_item( itemnum, subnum );    /* FILE transfer */
               break;
       case 1: Process_sys_item( itemnum ,subnum );     /* SYSTEM */
               break;
       case 2: crcflag = xfrmode = itemnum;             /* MODE */
               break;
       case 3: Process_serial_item( itemnum, subnum );  /* SERIAL */
               break;
       case 5: Process_debug_item( itemnum, subnum );   /* DEBUG */
               break;
       case 4:                                          /* PHONE */
               if( itemnum == 1 )  /* alternate long dist serv */
               {
                  altservflg = TRUE;
                  PhoneItem[1].Flags |= CHECKED;
               }
               else if( itemnum == 0 )  /* hang up */
               {
                   hang_up();
               }
               else if( pdir[ itemnum-2 ].number[0] != NULL)
               {/* dial resets altservflg, we reset checkmark */
                   itemnum -= 2;
                   list_plib( itemnum );
                   set_baud(atoi(pdir[ itemnum ].baud));
                   dial(pdir[ itemnum ].number);
                   PhoneItem[1].Flags &= ~CHECKED;
                   if(install.keyload)
                     Load_keymacros(pdir[ itemnum ].name);
               }
               break;
    }
}

Process_debug_item(itemnum, subnum)
USHORT itemnum, subnum;
{
   if(debug & (1 << itemnum))   /* if bit is set */
   {
      debug &= ~(1 << itemnum);  /* reset it */
      DebugItems[itemnum].Flags &= ~CHECKED;
   }
   else
   {
      debug |= (1 << itemnum);   /* else, set it */
      DebugItems[itemnum].Flags |= CHECKED;
      lcnt = 0;
   }
}

/************************************************************************
   Process the menu event the user desires.  This processing was delayed
   until the user entered a filename using the string input requester.
*/
void Process_menu_event( menu_event )
{
  UBYTE fname[ MAXFNAME + 41 ];
  int   temp;

  fname[0] = NULL;
  if(index(name,':') == 0)
     strcpy(fname,install.def_dir);
  strcat(fname,name);

  *name = NULL;

  switch (menu_event)
    {
      case NULL:   break;
      case ASCCAPT:
                   if(file_exists(fname))       /* requested file exists */
                   {
                      if(!use_file(fname))      /* he wants a new one */
                      {
                          menu_event = NULL;
                          strcpy(name,fname);
                          Process_file_item(0,0);
                          break;
                      }
                      else                      /* no: use the old one */
                          if( app_del() )
                              tranr = open(fname,O_WRONLY); /* append data */
                          else
                              tranr = open(fname,CREATE);
                   }
                   else
                     tranr = open(fname,CREATE);
                   if (tranr == ERROR)
                   {
                       capture = capton = FALSE;
                       sprintf(sbuff,"\nError Opening File %s\n",fname);
                       emits_rx(sbuff);
                       break;
                   }
                   capt_status = stat[C_ON];
                   status_line(75,capt_status);
                   capton = capture = TRUE;
                   bcount = 0;
                   RefreshStatus();
                   lseek(tranr,0L,2);
                   break;
      case ASCSEND:
                   if ((trans = fopen(fname,"r")) == 0)
                   {
                     send = FALSE;
                     sprintf(sbuff,"\nError Opening File %s\n",fname);
                     emits_rx(sbuff);
                     break;
                   }
                  sdelay = ((ULONG)propinfo.HorizPot >> 12);
                  send = TRUE;
                  break;
      case WXMRECV:  wxflag = TRUE;
      case XMDRECV:
                    if(file_exists(fname))
                       if(!use_file(fname))
                       {
                           menu_event = NULL;
                           Process_file_item(2,0);
                           break;
                        }
                    Set_Menus(OFF);         /* Ghost the menus */
                    if(test_4_arc(fname))   /* turn off auto chopping for */
                       chopflg = FALSE;     /* .ARC files */
                    if(viewflg) WindowToFront(vw_window);
                    if (XMODEM_Read_File(fname))
                        emits_rx("\nReceived File\n");
                    else
                      {
                        close(fd);
                        emits_rx("\nXmodem Receive Failed\n");
                      }
                     clear_status_line(); status_line(75,capt_status);
                     Set_Menus(ON);
                     Beep();
                     Xconfig(FALSE);  wxflag = FALSE;
                     chopflg = tmpchopflg;   /* restore CHOP mode flag */
                     if(abort)
                        emits_rx("User aborted transfer\n");
                     break;
      case XMDSEND:
                     if(!file_exists(fname))
                     {
                        no_file();         /* No such file requester */
                        menu_event = NULL;
                        Process_file_item(4,0); /* get another name */
                        break;
                     }
                     Set_Menus(OFF);
                     if(viewflg) WindowToFront(vw_window);
                     if (XMODEM_Send_File(fname))
                         emits_rx("\nFile Sent\n");
                     else
                       {
                         close(fd);
                         emits_rx("\nXmodem Send Failed\n");
                       }
                     clear_status_line(); status_line(75,capt_status);
                     Set_Menus(ON);
                     Beep();
                     Xconfig(FALSE);
                     asciiflg = FALSE;
                     if(abort)
                        emits_rx("User aborted transfer\n");
                     break;
      case EDITMAC:  Add_keymacro();
                     break;
      case LOADPHONE:temp = load_plib(strbuff);
                     if(temp)
                        ph_nums = temp;
                     break;
      case LOADKEYS: Load_keymacros(strbuff);
                     break;
      case SAVEKEYS: Save_keymacros(strbuff);
                     break;
    }
  Swap_capture(ASCCAPT,capture != TRUE);
  Swap_capture(ASCSEND,send    != TRUE);
  menu_event = NULL;
}

/************************************************************************/
void Process_file_item( itemnum, subnum )
USHORT itemnum, subnum;
{
  Activate(&Dirgadget);
  crcflag = xfrmode;    /* restore selected xfer mode */
  switch( itemnum )
  {
       case 0:
               if (capture == TRUE)
                 {
                   capton = capture = FALSE;
                   flush();
                   close(tranr);
                   emits_rx("\nEnd File Capture\n");
                   Swap_capture(ASCCAPT,START);
                   capt_status = stat[C_OFF];
                   status_line(75,capt_status);  /* remove ON/SUS on screen */
                 }
               else
                   if(getfile("Ascii Capture filename",name))
                      Process_menu_event( ASCCAPT );
                     RefreshStatus();
               break;
       case 1:
               if (send == TRUE)
               {
                 send = FALSE;
                 fclose(trans);
                 Xon(xonflg);
                 emits_rx("\nFile Send Canceled\n");
                 Swap_capture(ASCSEND,START);
               }
               else
                   if(getfile("Ascii Send filename",name))
                      Process_menu_event( ASCSEND );
               break;
       case 2:
               tmpchopflg = chopflg;
               if(getfile("Xmodem Receive filename",name))
                  Process_menu_event( XMDRECV );
               break;
       case 3:
               tmpchopflg = chopflg;
               if(getfile("WXmodem Receive filename",name))
                 Process_menu_event( WXMRECV );
               break;
       case 5:
               asciiflg = TRUE;
       case 4:
               if(getfile("Xmodem Send filename",name))
                 Process_menu_event( XMDSEND );
               else asciiflg = FALSE;
               break;
       case 6: KeepGoing = FALSE;
               break;
             }
}

#define FLUSH (-2)

buffer_it(ch)
int ch;
{
   if( ((ch == FLUSH) && bcount) || (bcount == BufSize) )
   {                                /* write any data in the buffer */
     if(write(tranr,buffer,bcount) != bcount)
     {
         emits_rx("ERROR writing to file.  File closed\n");
         close(tranr);
         capton = capture = FALSE;
     }
     bcount = 0;
   }
   buffer[ bcount++ ] = ch;          /* buffer the character */
}

flush()
{
   buffer_it( FLUSH );
}

/************************************************************************
   set serial port to desired baud rate
*/
void Process_baud_rate( itemnum )
USHORT itemnum;
{
   int baudrate;

   switch( itemnum )
     {
        case 0: baudrate = 300;   break;
        case 1: baudrate = 1200;  break;
        case 2: baudrate = 2400;  break;
        case 3: baudrate = 4800;  break;
        case 4: baudrate = 9600;  break;
        case 5: baudrate = 19200; break;
        default: return;
     }
     set_baud( baudrate );
}

/*************************************************************************
   process system menu selection.
*/
void Process_sys_item( itemnum, subnum )
USHORT itemnum, subnum;
{
   UBYTE temp[80];

   DeActivate(&Dirgadget);
   menu_event = NULL;

   switch ( itemnum )
      {
         case 0:
                  if(split_screen)
                  {
                     Single_Window();
                     SysItems[0].Flags &= ~CHECKED;
                  }
                  else
                  {
                       if( Split_Window() )
                         split_screen = TRUE;
                  }
                  break;
         case 1:
                    if(viewflg)    /* if view window open, close it */
                    {
                       viewflg = FALSE;
                       SysItems[1].Flags &= ~CHECKED;
                       close_view = TRUE;
                    }
                  else    /* else open view window */
                    {
                      viewflg = TRUE;
                      if( ( vw_window = (struct Window *)
                         MyOpenWindow(&VWindow,(ULONG)CLOSEWINDOW | GADGETUP)) == NULL)
                         {
                           emits_rx("Can't open view window\n");
                           viewflg = FALSE;
                         }
                      else
                      {
                          vw_con = CreateStdIO(vw_con_mp);
                          open_console(vw_window,vw_con);
                          WindowToFront(vw_window);
                      }
                    }
                  break;
         case 2:
                  if(chopflg)    /* fix the chop mode checkmark to match */
                     SysItems[2].Flags &= ~CHECKED;  /* the mode desired */
                  else
                     SysItems[2].Flags |=  CHECKED;
                  chopflg = !chopflg;
                  break;
         case 3:
                  switch(subnum)
                  {
                     case 0:  eolflg &=  RXCRLF; break;
                     case 1:  eolflg |= ~RXCRLF; break;
                     case 2:  eolflg &=  TXCRLF; break;
                     case 3:  eolflg |= ~TXCRLF; break;
                  }
                  break;
         case 4:
                  switch(subnum)
                  {
                     case 0:  strcpy(strbuff,commkeys);
                              if(getstring("LOAD","Key macro file",strbuff,MAXFNAME)== FALSE)
                                 break;
                              menu_event = LOADKEYS;
                              strcpy(commkeys,strbuff);
                              break;
                     case 1:  strcpy(strbuff,commkeys);
                              if(getstring("SAVE","Key macro file",strbuff,MAXFNAME)==FALSE)
                                 break;
                              menu_event = SAVEKEYS;
                              strcpy(commkeys,strbuff);
                              break;
                     case 2:
                              Edit_keymacro();
                              menu_event = EDITMAC;
                              break;
                 }
                 break;
         case 5:
                 switch(subnum)
                 {
                    case 0:  strcpy(strbuff,phonedir);
                             if(getstring("LOAD","Phone library",strbuff,MAXFNAME)== FALSE)
                                break;
                             menu_event = LOADPHONE;
                             strcpy(phonedir,strbuff);
                             break;
                    case 1:             /* no SAVE option yet */
                             break;
                    case 2:
                             strcpy(temp,"C:ED          ");
                             strcat(temp,phonedir);
                             WBenchToFront();
                             ShowTitle(commscreen,1L);
                             Execute(temp,0L,0L);
                             ShowTitle(commscreen,install.titlebar);
                             WBenchToBack();
                             break;
                 }
                 break;
         case 6:     /* title bar */
                 install.titlebar = (long)subnum;
                 ShowTitle(commscreen,install.titlebar);
                 break;
         }
}

DeActivate(gadg)
struct Gadget *gadg;
{
   gadg->Flags |= GADGDISABLED;
}

Activate(gadg)
struct Gadget *gadg;
{
   gadg->Flags &= ~GADGDISABLED;
}


/************************************************************************/
void Process_serial_item( itemnum, subnum )
USHORT itemnum, subnum;
{
   switch( itemnum )
     {
        case 0:
                  Process_baud_rate( subnum );    /* BAUD rate */
                  break;
        case 1:   Setparity( subnum );            /* parity */
                  break;
        case 2:   Setlength( subnum );            /* word length */
                  break;
        case 3:   Setstopbits( subnum );          /* stop bits */
                  break;
        case 4:   halfduplex = subnum;            /* duplex */
                  break;
        case 5:   xonflg = subnum;                /* XON/XOFF */
                  Xon(xonflg);
                  break;
        case 6:   SendBreak();                    /* send break */
                  break;
     }
}

/**************************************************************************
   Initialize the system.  Open windows, libraries and devices.  Exit
   cleanly if any trouble intializing.
*/
void InitSystem(argc,argv)
int argc;
UBYTE **argv;
{
  struct WBArg *wbarg;
  struct DiskObject *diskobj, *GetDiskObject();
  struct WBStartup *wb_msg;
  struct Library   *DOSbase;
  struct Preferences Pref;

  int    i,args;
  char  *ttype, *FindToolType();
  UBYTE *temp;

  DOSbase = (struct Library *)OpenLibrary(DOSNAME,0L);
  if(DOSbase)
    dos_version = DOSbase->lh_Version;

  IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",(long)dos_version);
  if( IntuitionBase == NULL )
     clean_up("Can't open intuition library\n");

  GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",(long)dos_version);
  if( GfxBase == NULL )
     clean_up("Can't open graphics library\n");

  args = argc;

  if(argc == 0)                     /* called from WorkBench */
  {
    if((IconBase = (ULONG)OpenLibrary(ICONNAME,0L)) == NULL)
       clean_up("Can't open Icon library\n");

    PlibItems[ 2 ].Flags &= ~ITEMENABLED;  /* can't use ED */
    wb_msg = (struct WBStartup *)argv;
    wbarg = wb_msg->sm_ArgList;

    diskobj = GetDiskObject(wbarg->wa_Name);
    if( diskobj != NULL )        /* get default files from .info file */
    {
       ttype = NULL;
       ttype = FindToolType(diskobj->do_ToolTypes,"PHONE");
       if(ttype)
         strcpy(phonedir,ttype);
       ttype = FindToolType(diskobj->do_ToolTypes,"KEYS");
       if(ttype)
         strcpy(commkeys,ttype);
       ttype = FindToolType(diskobj->do_ToolTypes,"INTERLACE");
         install.interlace = (strcmp(ttype,"ON") == 0);
       FreeDiskObject( diskobj );
    }
  }
  else
  {
    Defdir();                       /* find default directory */

    for(i = 1; i < argc; i++)
    {
       temp = argv[ i ];
       if(*temp++ == '-')
       {
          args--;
          while(*temp == 'i' || *temp == 'I')
          {
             install.interlace = TRUE; temp++;
          }
       }
       else
          strcat(phonedir,argv[ i ]);
    }
  }

  if(*phonedir == NULL)  strcpy(phonedir,PHONELIB);

  if(dos_version == DOS12)
  {
     RXWindow.Height    = GfxBase->NormalDisplayRows - 10;
     RXWindow.MinHeight = GfxBase->NormalDisplayRows - 52;
     STWindow.TopEdge   = GfxBase->NormalDisplayRows - 10;
     TXWindow.Height    = GfxBase->NormalDisplayRows - 10;
     CommScreen.Height  = GfxBase->NormalDisplayRows;
  }
  if(install.interlace)
  {
     CommScreen.ViewModes |= LACE;

     CommScreen.Height <<= 1;
     RXWindow.Height   <<= 1; RXWindow.TopEdge <<= 1; RXWindow.MinHeight <<= 1;
     STWindow.TopEdge  <<= 1; STWindow.TopEdge +=  8;
     TXWindow.Height   <<= 1; TXWindow.TopEdge <<= 1; TXWindow.MinHeight <<= 1;
     VWindow.Height    <<= 1; VWindow.TopEdge  <<= 1; VWindow.MaxHeight  <<= 1;
  }

/* allocate disk buffer for XMODEM must have at least 16 buffers */
  for(numbufs = install.numbuffs; numbufs > 15; numbufs -= 8)
    if( (diskbuff = malloc( numbufs * SECSIZ)) != NULL)
      break;
  if(diskbuff == NULL)
      clean_up("Can't allocate disk buffers\n");

  GetPrefs(&Pref,4L);

  commscreen = OpenScreen(&CommScreen);
  if(commscreen == 0)
     clean_up("Can't open screen\n");

  prefbaud = Pref.BaudRate -1;
  RXWindow.Screen = STWindow.Screen = TXWindow.Screen = VWindow.Screen =
      STwindow.Screen = RQWindow.Screen = commscreen;

  if(( tx_window = OpenWindow(&TXWindow) ) == NULL)
     clean_up("Can't open window\n");

  ViewPort = ViewPortAddress(tx_window);
  if(install.new_colors[0] | install.new_colors[1] | install.new_colors[2]
   | install.new_colors[3])
     LoadRGB4(ViewPort,install.new_colors,4L);

  add_window_gadgets(tx_window);
  rx_window = tx_window;

  if(( stat_window = OpenWindow(&STWindow)) == NULL)
     clean_up("Can't open window\n");

  ShowTitle(commscreen,0L);

  if( init_serial() == FALSE)
     clean_up("Can't open serial device\n");
  if(Open_Timer())
      clean_up("Can't open timer device\n");
  timeron = TRUE;
  InitBeep();

  tx_con_mp = CreatePort("tx_con_mp",0L);
  rx_con_mp = CreatePort("rx_con_mp",0L);
  st_con_mp = CreatePort("st_con_mp",0L);
  vw_con_mp = CreatePort("vw_con_mp",0L);

  tx_con = CreateStdIO(tx_con_mp);
  rx_con = CreateStdIO(rx_con_mp);
  st_con = CreateStdIO(st_con_mp);

  if( open_console(tx_window,tx_con) ||
      open_console(rx_window,rx_con) ||
      open_console(stat_window,st_con) )
        clean_up("Error opening console device\n");
  clear_status_line();

  this_process = (struct Process *)FindTask(0L);
  if(this_process)
  {
    err_window = this_process->pr_WindowPtr;
    this_process->pr_WindowPtr = (APTR)rx_window;
  }
  sprintf(sbuff,"\n\t\t\t\t%s\n\n",install.version);
  emits_rx(sbuff);
}

/**********************************************************************/
clean_up(message)
char *message;
{
  if(message)  puts(message);

  Modem_exit();         /* send parting string to modem */
  Close_Beep();         /* close audio...etc. */
  if( timeron )          Close_Timer();
  if( diskbuff )         free( diskbuff );
  Free_keymacros();

  Close_Serial();       /* close serial and deallocate port and memory */

  if(rx_con)
  {
     close_console(rx_con);  /* close open console device */
     DeleteStdIO(rx_con);
  }
  if(st_con)
  {
     close_console(st_con);  /* close open console device */
     DeleteStdIO(st_con);
  }
  if(tx_con)
  {
     close_console(tx_con);  /* close open console device */
     DeleteStdIO(tx_con);
  }
  if(vw_con)
  {
     close_console(vw_con);  /* close open console device */
     DeleteStdIO(vw_con);
  }
  if(tx_con_mp)     DeletePort(tx_con_mp);
  if(vw_con_mp)     DeletePort(vw_con_mp);
  if(rx_con_mp)     DeletePort(rx_con_mp);
  if(st_con_mp)     DeletePort(st_con_mp);

  if(this_process)
    this_process->pr_WindowPtr = err_window;

  if(req_window)        /* if requester left around, get rid of it */
     MyCloseWindow( req_window );

/* close all windows...in order */
  if(stat_window)        CloseWindow( stat_window );
  if(st_window)          MyCloseWindow( st_window );
  if(vw_window )         MyCloseWindow( vw_window );
  if(split_screen)       MyCloseWindow( rx_window );

  if(tx_window)
   {
     ClearMenuStrip( tx_window );
     CloseWindow( tx_window );
   }

   if(commscreen)
      CloseScreen(commscreen);

  if(IntuitionBase)      CloseLibrary(IntuitionBase);
  if(GfxBase)            CloseLibrary(GfxBase);
  if(IconBase)           CloseLibrary(IconBase);
  exit(1);
}

/* end of comm 1.34 */

