[comp.sources.amiga] v02i036: VT100 R2.7

doc@s.cc.purdue.edu (Craig Norborg) (10/03/87)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# Xshar: Extended Shell Archiver.
# This is part  2 out of  3.
# This archive created: Sat Oct  3 01:36:26 1987
# By: Craig Norborg (Purdue University Computing Center)
#	Run the following text with /bin/sh to create:
#	expand.c
#	init.c
#	kermit.c
#	remote.c
cat << \SHAR_EOF > expand.c
/*************************************************************
 * vt100 terminal emulator - Wild card and Directory support
 *
 *	v2.7 870825 ACS - Use the *InfoMsg*() routines in window.c rather
 *			  than req().
 *	v2.6 870227 DBW - bug fixes for all the stuff in v2.5
 *	v2.5 870214 DBW - more additions (see readme file)
 *	v2.4 861214 DBW - lots of fixes/additions (see readme file)
 *	v2.3 861101 DBW - minor bug fixes
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW	- new features (see README)
 *           860830 Steve Drew Added Wild card support,
 *		    features(expand.c)
 *	v2.0 860809 DBW - Major rewrite
 *	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW	- First version released
 *
 *      Much of the code from this module extracted from
 *      Matt Dillons Shell program. (Thanxs Matt.)
 *************************************************************/

#include "vt100.h"

struct DPTR {                    /* Format of directory fetch ptr */
   struct FileLock *lock;        /* lock on directory   */
   struct FileInfoBlock *fib;    /* mod'd fib for entry */
};

/*
 * Disk directory routines
 *
 *
 * diropen() returns a struct DPTR, or NULL if the given file does not
 * exist.  stat will be set to 1 if the file is a directory.  If the
 * name is "", then the current directory is openned.
 *
 * dirnext() returns 1 until there are no more entries.  The **name and
 * *stat are set.  *stat = 1 if the file is a directory.
 *
 * dirclose() closes a directory channel.
 *
 */

struct DPTR *
diropen(name, stat)
char *name;
int *stat;
{
   struct DPTR *dp;
   int namelen, endslash = 0;
   struct FileLock *MyLock;

   MyLock = (struct FileLock *)( (ULONG) ((struct Process *)
				 (FindTask(NULL)))->pr_CurrentDir);
   namelen = strlen(name);
   if (namelen && name[namelen - 1] == '/') {
      name[namelen - 1] = '\0';
      endslash = 1;
   }
   *stat = 0;
   dp = (struct DPTR *)malloc(sizeof(struct DPTR));
   if (*name == '\0')
      dp->lock = (struct FileLock *)DupLock (MyLock);
   else
      dp->lock = (struct FileLock *)Lock (name, ACCESS_READ);
   if (endslash)
      name[namelen - 1] = '/';
   if (dp->lock == NULL) {
      free (dp);
      return (NULL);
   }
   dp->fib = (struct FileInfoBlock *)
	 AllocMem((long)sizeof(struct FileInfoBlock), MEMF_PUBLIC);
   if (!Examine (dp->lock, dp->fib)) {
      dirclose (dp);
      return (NULL);
   }
   if (dp->fib->fib_DirEntryType >= 0)
      *stat = 1;
   return (dp);
}

dirnext(dp, pname, stat)
struct DPTR *dp;
char **pname;
int *stat;
{
   if (dp == NULL)
      return (0);
   if (ExNext (dp->lock, dp->fib)) {
      *stat = (dp->fib->fib_DirEntryType < 0) ? 0 : 1;
      *pname = dp->fib->fib_FileName;
      return (1);
   }
   return (0);
}


dirclose(dp)
struct DPTR *dp;
{
   if (dp == NULL)
      return (1);
   if (dp->fib)
      FreeMem (dp->fib, (long)sizeof(*dp->fib));
   if (dp->lock)
      UnLock (dp->lock);
   free (dp);
   return (1);
}

free_expand(av)
char **av;
{
   char **base = av;

   if (av) {
      while (*av) {
	 free (*av);
	 ++av;
      }
      free (base);
   }
}

/*
 * EXPAND(wild_name, pac)
 *    wild_name      - char * (example: "df0:*.c")
 *    pac            - int  *  will be set to # of arguments.
 *
 */


char **
expand(base, pac)
char *base;
int *pac;
{
   char **eav = (char **)malloc (sizeof(char *));
   int  eleft, eac;

   char *ptr, *name;
   char *bname, *ename, *tail;
   int stat, scr;
   struct DPTR *dp;

   *pac = eleft = eac = 0;
   base = strcpy(malloc(strlen(base)+1), base);
   for (ptr = base; *ptr && *ptr != '?' && *ptr != '*'; ++ptr);
   for (; ptr >= base && !(*ptr == '/' || *ptr == ':'); --ptr);
   if (ptr < base) {
      bname = strcpy (malloc(1), "");
   } else {
      scr = ptr[1];
      ptr[1] = '\0';
      bname = strcpy (malloc(strlen(base)+1), base);
      ptr[1] = scr;
   }
   ename = ptr + 1;
   for (ptr = ename; *ptr && *ptr != '/'; ++ptr);
   scr = *ptr;
   *ptr = '\0';
   tail = (scr) ? ptr + 1 : NULL;

   if ((dp = diropen (bname, &stat)) == NULL  ||  stat == 0) {
      free (bname);
      free (base);
      free (eav);
      InfoMsg1Line("Could not open directory");
      return (NULL);
   }
   while (dirnext (dp, &name, &stat)) {
      if (compare_ok(ename, name)) {
	 if (tail) {
	    int alt_ac;
	    char *search, **alt_av, **scrav;
	    struct FileLock *lock;

	    if (!stat)      /* expect more dirs, but this not a dir */
	       continue;
	    lock = (struct FileLock *)CurrentDir (dp->lock);
	    search = malloc(strlen(name)+strlen(tail)+2);
	    strcpy (search, name);
	    strcat (search, "/");
	    strcat (search, tail);
	    scrav = alt_av = expand (search, &alt_ac);
	    CurrentDir (lock);
	    if (scrav) {
	       while (*scrav) {
		  if (eleft < 2) {
		     char **scrav = (char **)
			malloc(sizeof(char *) * (eac + 10));
		     movmem (eav, scrav, sizeof(char *) * (eac + 1));
		     free (eav);
		     eav = scrav;
		     eleft = 10;
		  }
		  eav[eac] = malloc(strlen(bname)+strlen(*scrav)+1);
		  strcpy(eav[eac], bname);
		  strcat(eav[eac], *scrav);
		  free (*scrav);
		  ++scrav;
		  --eleft, ++eac;
	       }
	       free (alt_av);
	    }
	 } else {
	    if (eleft < 2) {
	       char **scrav = (char **)
		    malloc(sizeof(char *) * (eac + 10));
	       movmem (eav, scrav, sizeof(char *) * (eac + 1));
	       free (eav);
	       eav = scrav;
	       eleft = 10;
	    }
	    eav[eac] = malloc (strlen(bname)+strlen(name)+1);
	    eav[eac] = strcpy(eav[eac], bname);
	    strcat(eav[eac], name);
	    --eleft, ++eac;
	 }
      }
   }
   dirclose (dp);
   *pac = eac;
   eav[eac] = NULL;
   free (bname);
   free (base);
   if (eac)
      return (eav);
   free (eav);
   return (NULL);
}

/*
 * Compare a wild card name with a normal name
 */

#define MAXB   8

compare_ok(wild, name)
char *wild, *name;
{
   char *w = wild;
   char *n = name;
   char *back[MAXB][2];
   int  bi = 0;

   while (*n || *w) {
      switch (*w) {
      case '*':
	 if (bi == MAXB) {
	    InfoMsg1Line("Too many levels of '*'");
	    return (0);
	 }
	 back[bi][0] = w;
	 back[bi][1] = n;
	 ++bi;
	 ++w;
	 continue;
goback:
	 --bi;
	 while (bi >= 0 && *back[bi][1] == '\0')
	    --bi;
	 if (bi < 0)
	    return (0);
	 w = back[bi][0] + 1;
	 n = ++back[bi][1];
	 ++bi;
	 continue;
      case '?':
	 if (!*n) {
	    if (bi)
	       goto goback;
	    return (0);
	 }
	 break;
      default:
	 if (toupper(*n) != toupper(*w)) {
	    if (bi)
	       goto goback;
	    return (0);
	 }
	 break;
      }
      if (*n)  ++n;
      if (*w)  ++w;
   }
   return (1);
}

set_dir(new)
char *new;
{
   register 	char 		*s;
   int   			i;
   struct 	FileLock 	*lock;
   char 			temp[60];
   struct       FileInfoBlock   *fib;

   if (*new != '\000') {
      strcpy(temp, MyDir);
      s = new;
      if (*s == '/') {
	 s++;
	 for (i=strlen(MyDir);
	      MyDir[i] != '/' && MyDir[i] != ':';
	      i--);
	 MyDir[i+1] = '\0';
	 strcat(MyDir, s);
	 }
      else if (exists(s, ':') == 0) {
	 if (MyDir[strlen(MyDir)-1] != ':')
	    strcat(MyDir, "/");
	 strcat(MyDir, s);
	 }
      else
	 strcpy(MyDir, s);

      if ((lock = (struct FileLock *)Lock(MyDir, (long)ACCESS_READ)) == 0) {
	 InfoMsg2Line("Directory not found:",MyDir);
	 strcpy(MyDir, temp);
	 }
      else {
	 fib = (struct FileInfoBlock *)AllocMem(
		(long)sizeof(struct FileInfoBlock), MEMF_PUBLIC);
	 if (fib) {
	    if (Examine(lock, fib)) {
		if (fib->fib_DirEntryType > 0) {
		    CurrentDir(lock);
		    if (MyDirLock != NULL) UnLock(MyDirLock);
		    MyDirLock = lock;
		    if (MyDir[strlen(MyDir)-1] == '/')
			MyDir[strlen(MyDir)-1] = '\000';
		    }
		else {
		    InfoMsg2Line("Not a Directory:",MyDir);
		    strcpy(MyDir,temp);
		    }
		}
	    FreeMem(fib, (long)sizeof(struct FileInfoBlock));
	    }
	else {
	    InfoMsg1Line("Can't change directory...No free memory!");
	    strcpy(MyDir,temp);
	    }
	}
    }
}

exists(s,c)
char *s,c;
    {
    while (*s != '\000')
	if (*s++ == c) return(1);
    return(0);
    }
SHAR_EOF
cat << \SHAR_EOF > init.c
/***************************************************************
 * vt100 - terminal emulator - initialization
 *
 *	v2.7 870825 ACS - Allow execution of all script files specified on
 *			  command line (companion to changes in script.c).
 *			  Rolled menu init into one routine (do_menu_init()).
 *	v2.6 870227 DBW - bug fixes for all the stuff in v2.5
 *	v2.5 870214 DBW - more additions (see readme file)
 *	v2.4 861214 DBW - lots of fixes/additions (see readme file)
 *	v2.3 861101 DBW - minor bug fixes
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW - new features (see README)
 *	     860901 ACS - Added Parity and Word Length and support code
 *	     860823 DBW - Integrated and rewrote lots of code
 *	v2.0 860809 DBW - Major rewrite
 *	v1.1 860720 DBW - Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW - First version released
 *
 ***************************************************************/

#include "vt100.h"
#define FONTNAMESIZE	40
#define FONTSUFFIX	".font"
#define MAXFONTVARLEN	34	/* 40 minus sizeof(".font") */

/*   Used by script.c for script file chaining. */
int script_files_todo = 0;
char **script_files = NULL;

char line[256];

/* Command key equivalences per menu.  Manipulated by script.c */

/*   Equivalences for the File menu... */
struct filecmd {
    char ac;	/* ASCII Capture	*/
    char as;	/* ASCII Send		*/
    char xs;	/* Xmodem Send		*/
    char xr;	/* Xmodem Receive	*/
    char kg;	/* Kermit Get		*/
    char kr;	/* Kermit Receive	*/
    char ks;	/* Kermit Send		*/
    char kb;	/* Kermit Bye		*/
    char nl;
} filecmd_chars = { ' ', ' ', 'V', '^', 'G', 'R', 'S', 'B', '\0' };

/*   Equivalences for the Baud Rate sub-menu... */
struct baducmd {
    char b03;	/* 0300			*/
    char b12;	/* 1200			*/
    char b24;	/* 2400			*/
    char b48;	/* 4800			*/
    char b96;	/* 9600			*/
    char bnl;
} baudcmd_chars = { ' ', 'L', 'H', ' ', ' ', '\0' };

/*   Equivalences for the Parity sub-menu... */
struct parcmd {
    char no;	/* NOne			*/
    char ma;	/* MArk			*/
    char sp;	/* SPace		*/
    char ev;	/* EVen			*/
    char od;	/* ODd			*/
    char nl;
} parcmd_chars = { 'X', ' ', ' ', 'E', 'O', '\0' };

/*   Equivalences for the Xfer Mode sub-menu... */
struct modcmd {
    char im;	/* IMage		*/
    char tx;	/* TeXt			*/
    char cn;	/* CoNvert		*/
    char nl;
} modcmd_chars = { 'I', 'T', ' ', '\0' };

/*   Equivalences for the Script menu... */
struct scrcmd {
    char em;	/* Execute Macro	*/
    char ab;	/* Abort Macro		*/
    char nl;
} scrcmd_chars = { 'M', 'A', '\0' };

/*   Equivalences for the Utility menu... */
struct utilcmd {
    char sb;	/* Send Break	*/
    char hu;	/* Hang Up	*/
    char cd;	/* Change Dir	*/
    char cs;	/* Clear Screen	*/
    char ec;	/* ECho		*/
    char wr;	/* WRap		*/
    char nk;	/* Num Key	*/
    char ac;	/* App Cur	*/
    char bs;	/* BS<->DEL	*/
    char nl;
} utilcmd_chars = { '.', ' ', 'D', ' ', ' ', 'W', 'K', 'C', 'Z', '\0' };

static char myfontname[FONTNAMESIZE];
extern char *getenv();

static char *filetext[] = {
    "Ascii  Capture",
    "Ascii  Send",
    "Xmodem Receive",
    "Xmodem Send",
    "Kermit Get",
    "Kermit Receive",
    "Kermit Send",
    "Kermit BYE"
};

static char *commtext[] = {
    "Baud Rate",
    "Parity   ",
    "Xfer Mode"
};

static char *baudtext[] = {
    "   300",
    "  1200",
    "  2400",
    "  4800",
    "  9600"
};

static char *partext[] = {
    "  None ",
    "  Mark ",
    "  Space",
    "  Even ",
    "  Odd  "
};

static char *modtext[] = {
    "  Image  ",
    "  Text   ",
    "  Convert"
};

static char *scrtext[] = {
    "Execute Macro",
    "Abort Execution"
};

static char *utiltext[] = {
    "Send Break",
    "Hang Up",
    "Change Dir",
    "Clear Scrn",
    "  Echo",
    "  Wrap",
    "  Num Key",
    "  App Cur",
    "  BS<->DEL"
};

struct HowToInit {
    int LeftEdge;
    int Width;
    ULONG Flags;
    char **text;
    char *cmdkeys;
};

static struct HowToInit menu_init[] = {
	{ 0, 120+40, ITEMTEXT | ITEMENABLED | HIGHCOMP,
	     filetext, (char *)(&filecmd_chars) },
	{ 0, 88, ITEMTEXT | ITEMENABLED | HIGHCOMP,
	     commtext, NULL },
	{ 75, 56+40, ITEMTEXT | ITEMENABLED | HIGHCOMP | CHECKIT,
	       baudtext, (char *)(&baudcmd_chars) },
	{ 75, 56+40, ITEMTEXT | ITEMENABLED | HIGHCOMP | CHECKIT,
	      partext, (char *)(&parcmd_chars) },
	{ 75, 80+40, ITEMTEXT | ITEMENABLED | HIGHCOMP | CHECKIT,
	      modtext, (char *)(&modcmd_chars) },
	{ 0, 160, ITEMTEXT | ITEMENABLED | HIGHCOMP,
	     scrtext, (char *)(&scrcmd_chars) },
	{ 0, 88+40, ITEMTEXT | ITEMENABLED | HIGHCOMP,
	     utiltext, (char *)(&utilcmd_chars) }
};

#define FILE_INIT_ENTRY	(&(menu_init[0]))
#define COMM_INIT_ENTRY	(&(menu_init[1]))
#define RS_INIT_ENTRY	(&(menu_init[2]))
#define PAR_INIT_ENTRY	(&(menu_init[3]))
#define XF_INIT_ENTRY	(&(menu_init[4]))
#define SCRIPT_INIT_ENTRY	(&(menu_init[5]))
#define UTIL_INIT_ENTRY	(&(menu_init[6]))

void do_menu_init();

char *InitDefaults(argc,argv)
int	argc;
char	**argv;
    {
    FILE    *fd = NULL;
    char    *p, *t, *ifile;
    int     l, dont_init = 0;

    doing_init = 1;	/* make sure we only allow INIT script commands */
    if (argc > 1) {
	int start_of_script_files = 1;

	if(strcmp(argv[1], "-i") == 0) {	/* No init file */
	    dont_init = 1;
	    start_of_script_files = 2;
	}
	else if(strcmp(argv[1], "+i") == 0) {	/* Use specified init file */
	    start_of_script_files = 3;
    	    if((fd=fopen(argv[2],"r")) == NULL) {
		ifile = AllocMem((LONG)(strlen(argv[2])+3), MEMF_PUBLIC|MEMF_CLEAR);
		strcpy(ifile, "S:");
		strcat(ifile, argv[2]);
		fd = fopen(ifile, "r");
		FreeMem(ifile, (LONG)(strlen(argv[2])+3));
		ifile = NULL;
	    }
	}
	if(start_of_script_files > argc)
	    script_files_todo = 0;
	else
	    script_files_todo = argc - start_of_script_files; /* # of cmdline script files left */
	script_files = &(argv[start_of_script_files]);	  /* Ptr to first of 'em */
    }

    if(!dont_init)
	if((fd == NULL) && ((fd=fopen("vt100.init","r")) == NULL))
	    fd=fopen("s:vt100.init","r");

    if(fd != NULL) {
	while (fgets(line,256,fd) != 0) {
	    line[strlen(line)-1] = '\000';
	    p = next_wrd(&line[0],&l);
	    if (*p) {
		*p |= ' ';
		if (p[1]) p[1] |= ' ';
		if (*p == '#') continue;
		if (*p == 'e' && p[1] == 'x') break;
		exe_cmd(p,l);
		}
	}
	fclose(fd);
    }
    doing_init = 0;

    /* Now set up all the screen info as necessary */
    if (p_interlace == 0) {
	if (p_lines > 24) p_lines = 24;
	MINY = 14;
	NewWindow.Height    = (long)((p_lines*8)+8);
	}
    else {
	if (p_lines > 48) p_lines = 48;
	MINY = 16;
	NewScreen.ViewModes |= LACE;
	NewWindow.Height    = (long)((p_lines*8)+10);
	}
    NewWindow.MinHeight = NewWindow.Height;
    NewWindow.MaxHeight = NewWindow.Height;
    NewWindow.TopEdge	= 0L;
    MAXY = ((p_lines-1)*8) + MINY;
    top  = MINY;
    bot  = MAXY;
    savx = MINX;
    savy = MINY;
    if (p_screen == 1) {
	if (p_depth > 2) p_depth = 2;
	if (p_depth < 1) p_depth = 1;
	NewScreen.Depth     = (long)p_depth;
	NewScreen.Height    = (long)((p_lines*8)+16);
	if (p_interlace == 1)
	    NewScreen.TopEdge	= (long)(400 - NewScreen.Height);
	else
	    NewScreen.TopEdge	= (long)(208 - NewScreen.Height);
	}
    else {
	p_depth			= 2L;
	NewWindow.TopEdge	= 0L;
	NewWindow.Screen	= NULL;
	NewReqWindow.Screen	= NULL;
	NewWindow.Type		= WBENCHSCREEN;
	NewReqWindow.Type	= WBENCHSCREEN;
	}

	/* check for environment variable specifying font name */
	if((t = getenv("font"))) {
		if(strlen(t) <= MAXFONTVARLEN) {
			strcpy(myfontname,t);
			strcat(myfontname,FONTSUFFIX);
			myattr.ta_Name = (STRPTR)myfontname;
		} else
			fprintf(stderr,"font environment variable is too long.\n");
	}

    /* see if we exit with a startup script */
    if (*p == 'e') {
	p = next_wrd(p+l+1,&l);
	if (*p) return(p);
    }
    if (script_files_todo > 0) {
    	script_files_todo--;
    	return(*(script_files++));
    }
    return(NULL);
    }

void InitDevs()
{
USHORT	colors[4];
int	i;
BYTE	*b,*c;

IntuitionBase = (struct IntuitionBase *)
    OpenLibrary("intuition.library", INTUITION_REV);
if( IntuitionBase == NULL )
    cleanup("can't open intuition",1);

GfxBase = (struct GfxBase *)
    OpenLibrary("graphics.library",GRAPHICS_REV);
if( GfxBase == NULL )
    cleanup("can't open graphics library",2);

if (p_screen == 1) {
    if ((myscreen = (struct Screen *)OpenScreen(&NewScreen)) == NULL)
	cleanup("can't open screen",3);
    NewWindow.Screen = myscreen;
    NewReqWindow.Screen = myscreen;
    }

if ((mywindow = (struct Window *)OpenWindow(&NewWindow)) == NULL)
    cleanup("can't open window",4);
if ((myfont = (struct TextFont *)OpenFont(&myattr)) == NULL)
    cleanup("can't open font",4);

myviewport   = (struct ViewPort *)ViewPortAddress(mywindow);
myrastport   = (struct RastPort *)mywindow->RPort;

SetFont(myrastport,myfont);

if (p_depth > 1) myrequest.BackFill = 2;
if (p_screen != 0 && p_wbcolors == 0) {
    colors[0] = p_background;
    colors[1] = p_foreground;
    colors[2] = p_bold;
    colors[3] = p_cursor;
    if (p_depth == 1)
	LoadRGB4(myviewport,(struct ColorMap *)colors,2L);
    else
	LoadRGB4(myviewport,(struct ColorMap *)colors,4L);
    }

Read_Request = (struct IOExtSer *)
    AllocMem((long)sizeof(*Read_Request),MEMF_PUBLIC|MEMF_CLEAR);
Read_Request->io_SerFlags = 0L;
Read_Request->IOSer.io_Message.mn_ReplyPort = CreatePort(0L,0L);
if(OpenDevice(SERIALNAME,NULL,Read_Request,NULL))
    cleanup("Cant open Read device",5);
rs_in = malloc(p_buffer+1);
Read_Request->io_SerFlags = 0L;
Read_Request->io_Baud	  = p_baud;
Read_Request->io_ReadLen  = 8L;
Read_Request->io_WriteLen = 8L;
Read_Request->io_CtlChar  = 0x11130000L;
Read_Request->io_RBufLen  = p_buffer;
Read_Request->io_BrkTime  = p_break;
Read_Request->IOSer.io_Command = SDCMD_SETPARAMS;
DoIO(Read_Request);
Read_Request->IOSer.io_Command = CMD_READ;
Read_Request->IOSer.io_Length  = 1;
Read_Request->IOSer.io_Data    = (APTR) &rs_in[0];

Write_Request = (struct IOExtSer *)
    AllocMem((long)sizeof(*Write_Request),MEMF_PUBLIC|MEMF_CLEAR);
b = (BYTE *)Read_Request;
c = (BYTE *)Write_Request;
for (i=0;i<sizeof(struct IOExtSer);i++) *c++ = *b++;
Write_Request->IOSer.io_Message.mn_ReplyPort = CreatePort(0L,0L);
Write_Request->IOSer.io_Command = CMD_WRITE;
Write_Request->IOSer.io_Length	= 1;
Write_Request->IOSer.io_Data	= (APTR) &rs_out[0];

Timer_Port = CreatePort("Timer Port",0L);
Script_Timer_Port = CreatePort("Timer Port",0L);

if (OpenDevice(TIMERNAME, UNIT_VBLANK, (char *) &Timer, 0) ||
    OpenDevice(TIMERNAME, UNIT_VBLANK, (char *) &Script_Timer, 0))
	cleanup("can't open timer device",7);

Timer.tr_node.io_Message.mn_ReplyPort = Timer_Port;
Timer.tr_node.io_Command = TR_ADDREQUEST;
Timer.tr_node.io_Flags = 0;
Timer.tr_node.io_Error = 0;

Script_Timer.tr_node.io_Message.mn_ReplyPort = Script_Timer_Port;
Script_Timer.tr_node.io_Command = TR_ADDREQUEST;
Script_Timer.tr_node.io_Flags = 0;
Script_Timer.tr_node.io_Error = 0;

BeepWave   = (UBYTE *)AllocMem(BEEPSIZE,(long)(MEMF_CHIP|MEMF_CLEAR));
if (BeepWave != 0) BeepWave[0] = 100;

Audio_Port = CreatePort("Audio Port",0L);

Audio_Request.ioa_Request.io_Message.mn_ReplyPort   = Audio_Port;
Audio_Request.ioa_Request.io_Message.mn_Node.ln_Pri = 85;
Audio_Request.ioa_Data		    = Audio_AllocMap;
Audio_Request.ioa_Length	    = (ULONG) sizeof(Audio_AllocMap);

if (OpenDevice(AUDIONAME, NULL, (char *) &Audio_Request, NULL))
	cleanup("can't open audio device",8);

Audio_Request.ioa_Request.io_Command	= CMD_WRITE;
Audio_Request.ioa_Request.io_Flags	= ADIOF_PERVOL;
Audio_Request.ioa_Data		= BeepWave;
Audio_Request.ioa_Length	= BEEPSIZE;
Audio_Request.ioa_Period	= COLORCLOCK / (BEEPSIZE * BEEPFREQ);
Audio_Request.ioa_Volume	= p_volume;
Audio_Request.ioa_Cycles	= 100;
}

/*****************************************************************/
/*    The following function initializes the structure arrays	 */
/*   needed to provide the File menu topic.			 */
/*****************************************************************/
void InitFileItems()
{
    do_menu_init(FileItem, FileText, FILE_INIT_ENTRY, FILEMAX);
}

/******************************************************************
/*			Main Comm menu
/*		set up for Baud & Parity submenus
/******************************************************************/
void InitCommItems()
{
    int n;

    do_menu_init(CommItem, CommText, COMM_INIT_ENTRY, COMMAX);
    CommItem[0].SubItem = RSItem;
    CommItem[1].SubItem = ParItem;
    CommItem[2].SubItem = XFItem;

/*****************************************************************/
/*    The following initializes the structure arrays		 */
/*   needed to provide the BaudRate Submenu topic.		 */
/*****************************************************************/

    do_menu_init(RSItem, RSText, RS_INIT_ENTRY, RSMAX);
    for( n=0; n<RSMAX; n++ ) {
	RSItem[n].MutualExclude = (~(1 << n));
    }

    /* select baud item chekced */
    switch (p_baud) {
	case 300:	n = 0; break;
	case 1200:	n = 1; break;
	case 2400:	n = 2; break;
	case 4800:	n = 3; break;
	case 9600:	n = 4; break;
	default:	n = 2; p_baud = 2400;
    }
    RSItem[n].Flags |= CHECKED;

/* initialize text for specific menu items */

/*****************************************************************/
/*    The following initializes the structure arrays		 */
/*   needed to provide the Parity   Submenu topic.		 */
/*****************************************************************/

    do_menu_init(ParItem, ParText, PAR_INIT_ENTRY, PARMAX);
    for( n=0; n<PARMAX; n++ ) {
	ParItem[n].MutualExclude = (~(1 << n));
    }

    /* select parity item chekced */
    ParItem[p_parity].Flags |= CHECKED;

/*****************************************************************/
/*    The following initializes the structure arrays		 */
/* initialize text for specific menu items */
/*    needed to provide the Transfer Mode menu topic.		 */
/*****************************************************************/

    do_menu_init(XFItem, XFText, XF_INIT_ENTRY, XFMAX);
    
    /* initialize each menu item and IntuiText with loop */
    for( n=0; n<XFMAX; n++ ) {
	if (n < 2)	XFItem[n].MutualExclude = 2 - n;
    }
    /* mode checked */
    XFItem[p_mode].Flags |= CHECKED;
    if (p_convert)	XFItem[2].Flags |= CHECKED;

/* initialize text for specific menu items */

} /* end of InitCommItems() */


/*****************************************************************/
/*    The following function initializes the structure arrays	 */
/*   needed to provide the Script menu topic.			 */
/*****************************************************************/
void InitScriptItems()
{
    do_menu_init(ScriptItem, ScriptText, SCRIPT_INIT_ENTRY, SCRIPTMAX);
}

/*****************************************************************/
/*    The following function initializes the structure arrays	 */
/*   needed to provide the Util menu topic.		       */
/*****************************************************************/
void InitUtilItems()
    {
    int	n;

    do_menu_init(UtilItem, UtilText, UTIL_INIT_ENTRY, UTILMAX);
/* initialize each menu item and IntuiText with loop */
    for( n=0; n<UTILMAX; n++ ) {
	if (n > 3) UtilItem[n].Flags |= CHECKIT;
    }

    if (p_echo)		UtilItem[4].Flags |= CHECKED;
    if (p_wrap)		UtilItem[5].Flags |= CHECKED;
    if (p_keyapp == 0)	UtilItem[6].Flags |= CHECKED;
    if (p_curapp)	UtilItem[7].Flags |= CHECKED;
    if (p_bs_del)	UtilItem[8].Flags |= CHECKED;
}

/****************************************************************/
/*   The following function inits the Menu structure array with */
/*  appropriate values for our simple menu.  Review the manual	*/
/*  if you need to know what each value means.			*/
/****************************************************************/
void InitMenu()
{
menu[0].NextMenu = &menu[1];
menu[0].LeftEdge = 5;
menu[0].TopEdge = 0;
menu[0].Width = 40;
menu[0].Height = 10;
menu[0].Flags = MENUENABLED;
menu[0].MenuName = "File";	  /* text for menu-bar display */
menu[0].FirstItem = &FileItem[0]; /* pointer to first item in list */

menu[1].NextMenu = &menu[2];
menu[1].LeftEdge = 55;
menu[1].TopEdge = 0;
menu[1].Width = 88;
menu[1].Height = 10;
menu[1].Flags = MENUENABLED;
menu[1].MenuName = "Comm Setup";   /* text for menu-bar display */
menu[1].FirstItem = &CommItem[0];  /* pointer to first item in list */

menu[2].NextMenu = &menu[3];
menu[2].LeftEdge = 153;
menu[2].TopEdge = 0;
menu[2].Width = 56;
menu[2].Height = 10;
menu[2].Flags = MENUENABLED;
menu[2].MenuName = "Script";	    /* text for menu-bar display */
menu[2].FirstItem = &ScriptItem[0]; /* pointer to first item in list*/

menu[3].NextMenu = NULL;
menu[3].LeftEdge = 225;
menu[3].TopEdge = 0;
menu[3].Width = 64;
menu[3].Height = 10;
menu[3].Flags = MENUENABLED;
menu[3].MenuName = "Utility";	   /* text for menu-bar display */
menu[3].FirstItem = &UtilItem[0];  /* pointer to first item in list*/
}

void do_menu_init(menuitem, menutext, initentry, max)
struct MenuItem menuitem[];
struct IntuiText menutext[];
struct HowToInit *initentry;
int max;
{
    int n, nplus1;
    char **temp;

    /* initialize each menu item and IntuiText with loop */
    for( n=0; n < max; n++ ) {
	nplus1 = n + 1;
	temp = initentry->text;
	menutext[n].IText = (UBYTE *)temp[n];
	menuitem[n].NextItem = &menuitem[nplus1];
	menuitem[n].LeftEdge = initentry->LeftEdge;
	menuitem[n].TopEdge = 10 * n;
	menuitem[n].Width = initentry->Width;
	menuitem[n].Height = 10;
	menuitem[n].Flags = initentry->Flags;
	menuitem[n].MutualExclude = 0;
	menuitem[n].ItemFill = (APTR)&menutext[n];
	menuitem[n].SelectFill = NULL;
	if((initentry->cmdkeys != NULL) && (initentry->cmdkeys[n] != ' ')) {
	    menuitem[n].Command  = initentry->cmdkeys[n];
	    menuitem[n].Flags   |= COMMSEQ;
	    }
	else menuitem[n].Command = 0;
	menuitem[n].SubItem = NULL;
	menuitem[n].NextSelect = 0;
    
	menutext[n].FrontPen = 0;
	menutext[n].BackPen = 1;
	menutext[n].DrawMode = JAM2;/* render in fore and background */
	menutext[n].LeftEdge = 0;
	menutext[n].TopEdge = 1;
	menutext[n].ITextFont = NULL;
	menutext[n].NextText = NULL;
	}
    menuitem[max-1].NextItem = NULL;
}
SHAR_EOF
cat << \SHAR_EOF > kermit.c
/*************************************************************
 * vt100 terminal emulator - KERMIT protocol support
 *
 *	v2.7 870825 ACS - Fixed the "multiple-send" problem in
 *			  doksend() et al; show status using the *InfoMsg*()
 *			  routines in window.c; fixed erroneous calls to
 *			  spack() and rpack(); better error handling.
 *	v2.6 870227 DBW - bug fixes for all the stuff in v2.5
 *	v2.5 870214 DBW - more additions (see readme file)
 *	v2.4 861214 DBW - lots of fixes/additions (see readme file)
 *	v2.3 861101 DBW - minor bug fixes
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW - new features (see README)
 *	     860901 ACS - Added eight bit quoting
 *	     860830 Steve Drew Wild card support, err recovry,bugs.
 *	     860823 DBW - Integrated and rewrote lots of code
 *	     860811 Steve Drew multi filexfer, bugs, status line ect..
 *	v2.0 860809 DBW - Major rewrite
 *	v1.1 860720 DBW - Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW - First version released
 *
 *************************************************************/

#include "vt100.h"

#define MAXPACKSIZ 94	    /* Maximum msgpkt size */
#define CR	   13	    /* ASCII Carriage Return */
#define LF	   10	    /* ASCII line feed */
#define SP	   32	    /* ASCII space */
#define DEL	  127	    /* Delete (rubout) */

#define MAXTRY	  5	   /* Times to retry a msgpkt */
#define MYQUOTE  '#'	   /* Quote character I will use */
#define MYRPTQ	 '~'	   /* Repeat quote character */
#define MYEBQ	 '&'	   /* 8th bit prefix character */
#define MYPAD	   0	   /* Number of padding charss I will need */
#define MYPCHAR    0	   /* Padding character I need (NULL) */
#define MYEOL	 '\n'	   /* End-Of-Line character I need */

#define tochar(ch)  ((ch) + ' ')
#define unchar(ch)  ((ch) - ' ')
#define ctl(ch)     ((ch) ^ 64 )

/* Global Variables */

int
   sending,	/* Indicates that we're sending, not receiving */
   lastpkt,	/* Last successful packet # sent/received */
   size,	/* Size of present data */
   osize,	/* Size of last data entry */
   rpsiz,	/* Maximum receive msgpkt size */
   spsiz,	/* Maximum send msgpkt size */
   timint,	/* Time interval to wait */
   pad,		/* How much padding to send */
   n,		/* Packet number */
   tp,		/* total packets */
   numtry,	/* Times this msgpkt retried */
   retry,	/* total retries */
   oldtry,	/* Times previous msgpkt retried */
   sendabort,	/* flag for aborting send file  */
   rptflg,	/* are we doing repeat quoting */
   ebqflg,	/* are we doing 8th bit quoting */
   notfirst,	/* is this the first file received */
   first,	/* is this the first time in a file */
   rpt,		/* current repeat count */
   next,	/* what is the next character */
   t;		/* current character */
long
   totbytes;	/* total bytes xfered on this file */

char
   state,	/* Present state of the automaton */
   padchar,	/* Padding character to send */
   eol,		/* End-Of-Line character to send */
   quote,	/* Quote character in incoming data */
   rptq,	/* Quote character for repeats */
   ebq,		/* Quote character for 8th bit quoting */
   ackpkt[MAXPACKSIZ+20],	/* ACK/NAK packet buffer */
   msgpkt[MAXPACKSIZ+20],	/* Message Packet buffer */
   filnam[40],	/* remote file name */
   snum[10],
   mainmode[10];

FILE *fp;	/* file for send/receive */

char *
getfname(name)	/* returns ptr to start of file name from spec */
char *name;
    {
    int l;

    l = strlen(name);
    while(l && name[l] != '/' && name[l] != ':') l--;
    if (name[l] == '/' || name[l] == ':') l++;
    return(name += l);
    }

doksend(file,more)
char *file;
int more;
{
    int amount, c, wild;
    char *p, **list = NULL;

    sending = 1;
    if (!strcmp(file,"$")) { saybye(); return(USERABORT); }
    p = file;
    while(*p && *p != '*' && *p != '?') p++;
    if (*p) {
	wild = TRUE;
	list = expand(file, &amount);
	if (list == NULL) InfoMsg1Line("KERMIT: No wild card match");
    }
    else {
	wild = FALSE;
	amount = 1;
    }
    /*	  The "multiple send" problem is brought about by attempting to
    ** send multiple files in a single "batch" (via globbing, e.g. *.foo)
    ** to a remote kermit that is NOT in server mode.  A 'Z' packet
    ** (meaning end-of-file) is sent after each of the files with a 'B'
    ** packet (meaning end-of-batch) coming after the last 'Z' packet.
    ** The old code reset the packet # on each iteration.  We do it
    ** outside of the for loop. */
    n = lastpkt = 0;
    for (c = 0; c < amount; c++) {
	if (wild == TRUE) p = list[c];
	    else  p = file;
	strcpy(filnam,getfname(p));
	ttime = TTIME_KERMIT;
	tp = retry = numtry = 0; totbytes = 0L;
	if ((fp = fopen(p,"r")) == NULL) {
	    InfoMsg2Line("KERMIT: Can't open send file:", p);
	    continue;
	}
	strcpy(mainmode,"SEND");
	ClearBuffer();
	/*  This is another piece of the multiple-send fix.  Sendsw() needs
	** to know 1) that this is the first file so it can send a send-init
	** packet and 2) if this is the last file so it can send a B packet
	** to indicate end-of-batch.  The last piece of the multiple-send fix
	** is in sendsw() itself. */
	if ( sendsw(c == 0, c >= (amount-1)) ) /* Successful send? */
	    ScrollInfoMsg(1);
	fclose(fp);
    }
    free_expand(list);
    return(TRUE);
}

dokreceive(file,more)
char *file;
int more;
   {
   int retval;

   ttime = TTIME_KERMIT;
   sending = 0;
   if (!strcmp(file,"$")) { saybye(); return(USERABORT); }
   strcpy(filnam, file);
   if (server) strcpy(mainmode,"GET");
   else        strcpy(mainmode,"RECV");
   tp =  lastpkt = retry = n =  numtry = notfirst = 0; totbytes = 0L;
   ClearBuffer();
   retval  = recsw();
   return(retval);
   }

sendsw(firstfile, lastfile)
int firstfile, lastfile; /* Multiple-send fix */
   {
   char sinit(), sfile(), sdata(), seof(), sbreak();
   sendabort = 0;
   /* Multiple-send fix.  If this is the first file of the batch then enter
   ** send-init state otherwise just enter send-file state. */
   if(firstfile)
	state = 'S';
   else
	state = 'F';
   while(TRUE) {
      switch(state) {
	 case 'S':   state = sinit();  break;
	 case 'F':   state = sfile();  break;
	 case 'D':   state = sdata();  break;
	 case 'Z':   state = seof();   break;
	 case 'B':   if (lastfile || sendabort) {
			/* Multiple-send fix.  If this is the last file then
			** send a B packet to indicate end-of-batch. */
			state = sbreak();
			break;
		     }
		     else
			return(TRUE);	/* Otherwise, just return. */
	 case 'C':   if (sendabort) return(FALSE);
		     else return(TRUE);
	 case 'E':   dostats('E',"ERROR");  /* so print the err and abort */
		     print_host_err(ackpkt);
		     return(FALSE);
	 case 'A':   if (timeout == USERABORT) {
			 timeout = GOODREAD;
			 n = (n+1)%64;
			 sendabort = 1;
			 dostats('A',"ABORT");
			 strcpy(msgpkt, "D");
			 state = 'Z';
			 break;
			 }
		     if (timeout == TIMEOUT) dostats('A',"TMOUT");
		     else { /* protocol error dectected by us */
			 dostats('A',"ERROR");
			 print_our_err();
			 }
		     return(FALSE);
	 default:    return(FALSE);
	 }
      }
   }

char sinit()
   {
   int num, len;

   retry++;
   if (numtry++ > MAXTRY) return('A');
   spar(msgpkt);

   spack('S',n,9,msgpkt);
   switch(rpack(&len,&num,ackpkt)) {
      case 'N':  return(state);
      case 'Y':  if (n != num) return(state);
		 rpar(ackpkt);
		 if (eol == 0) eol = '\n';
		 if (quote == 0) quote = MYQUOTE;
		 numtry = 0;
		 retry--;
		 n = (n+1)%64;
		 return('F');
      case 'E':  return('E');
      case FALSE:if (timeout == USERABORT) state = 'A';
		 return(state);
      default:	 return('A');
      }
    }

char sfile()
   {
   int num, len;

   retry++;
   if (numtry++ > MAXTRY) return('A');

   spack('F',n,strlen(filnam),filnam);
   switch(rpack(&len,&num,ackpkt)) {
      case 'N':
	 num = (--num<0 ? 63:num);
	 if (n != num) return(state);
      case 'Y':
	 if (n != num) return(state);
	 numtry = 0;
	 retry--;
	 n = (n+1)%64;
	 first = 1;
	 size = getpkt();
	 return('D');
      case 'E':
	 return('E');
      case FALSE: if (timeout == USERABORT) state = 'A';
		  return(state);
      default:
	 return('A');
      }
   }

char sdata()
   {
   int num, len;

   retry++;
   if (numtry++ > MAXTRY) return('A');

   spack('D',n,size,msgpkt);
   switch(rpack(&len,&num,ackpkt)) {
      case 'N':
	 num = (--num<0 ? 63:num);
	 if (n != num) return(state);
      case 'Y':
	 if (n != num) return(state);
	 numtry = 0;
	 retry--;
	 n = (n+1)%64;
	 if ((size = getpkt()) == 0) return('Z');
	 return('D');
      case 'E':
	 return('E');
      case FALSE: if (timeout == USERABORT) state = 'A';
		  return(state);
      default:
	 return('A');
      }
   }

char seof()
   {
   int num, len;
   retry++;
   if (numtry++ > MAXTRY) return('A');

/*   if (timeout == USERABORT) {*/	/* tell host to discard file */
/*	timeout = GOODREAD;	*/
/*	  spack('Z',n,1,"D");	*/
/*	  }			*/
/*   else			*/
	spack('Z',n,sendabort,msgpkt);
   switch(rpack(&len,&num,ackpkt)) {
      case 'N':
	 num = (--num<0 ? 63:num);
	 if (n != num) return(state);
      case 'Y':
	 if (n != num) return(state);
	 numtry = 0;
	 dostats('Z',"DONE");
	 retry--;
	 n = (n+1)%64;
	 return('B');
      case 'E':
	 return('E');
      case FALSE: return(state);
      default:
	 return('A');
      }
   }

char sbreak()
   {
   int num, len;
   retry++;
   if (numtry++ > MAXTRY) return('A');

   spack('B',n,0,msgpkt);
   switch (rpack(&len,&num,ackpkt)) {
      case 'N':
	 num = (--num<0 ? 63:num);
	 if (n != num) return(state);
      case 'Y':
	 if (n != num) return(state);
	 dostats('B', "DONE");
	 numtry = 0;
	 retry--;
	 n = (n+1)%64;
	 return('C');
      case 'E':
	 return('E');
      case FALSE: return(state);
      default:	  return ('A');
      }
   }

/* timeout equals USERABORT so lets end the file and quit  */
/* when host receives 'Z' packet with "D" in data field he */
/* should discard the file.				   */
/*
sabort()
   {
   dostats(' ',"ABORT");
   n = (n+1)%64;
   retry--;
   state = 'Z';
   while (state == 'Z') state = seof();
   while (state == 'B') state = sbreak();
   return(FALSE);
   }
*/


recsw()
   {
   char rinit(), rfile(), rdata();
   int first_time = 1;

   state = 'R';

   while(TRUE) {
      switch(state) {
	 case 'R':   state = rinit(); break;
	 case 'Z':
	 case 'F':   state = rfile(first_time); first_time = 0; break;
	 case 'D':   state = rdata(); break;
	 case 'C':   return(TRUE);
	 case 'E':
	 case 'A':   /* easy way to cleanly abort
			should really send and ACK
			with "X" in data field and
			wait for host to abort but
			not all kermits support
			this feature.		*/
		    if (timeout == USERABORT){
			/* send an error packet back   */
			 dostats('A',"ABORT");
			 spack('E',n,12,"User aborted");
		     }
		     else if (timeout == TIMEOUT) {
			    /* we timed out waiting */
			    /* will we need to spack here ?*/
			 dostats('A',"TMOUT");
			 }
			    /* must be 'E' from host or we
			     detected a protocol error */
			 else dostats('A',"ERROR");

		     if (state == 'E') print_host_err(msgpkt);
		     else if (timeout == GOODREAD) /* tell host why */
			print_our_err();
			   /* will this kill all files ?*/
		     do  {
			 ttime = 2;
			 readchar();
			 }  while (timeout == GOODREAD);
		     fclose(fp);
		     sendstring("\r");
		     return(FALSE);
	 default:    return(FALSE);
	 }
      }
   }



char rinit()
   {
   int len, num;
   retry++;
   if (numtry++ > MAXTRY) return('A');

   if (server) spack('R',n,strlen(filnam),filnam);
   else  spack('N',n,0,"");
   switch(rpack(&len,&num,msgpkt)) {
      case 'S':
	 rpar(msgpkt);
	 spar(msgpkt);
	 spack('Y',n,9,msgpkt);
	 oldtry = numtry;
	 numtry = 0;
	 retry--;
	 n = (n+1)%64;
	 return('F');
      case 'E':
	 return('E');
      case 'N':		/* Other side NAKed us... */
	 return(state); /* ...so try again	  */
      case FALSE:
	 if (timeout == USERABORT) return('A');
	 if (timeout == TIMEOUT)   return(state); /* Resend Rec-init on a timeout */
	 spack('N',n,0,"");
	 return(state);
      default:
	 return('A');
      }
   }

char rfile(first_time)
int first_time;
   {
   int num, len;
   USHORT a, a7, b8;
   char *fileptr, *buf;

   retry++;
   if (numtry++ > MAXTRY) return('A');

   switch(rpack(&len,&num,msgpkt)) {
      case 'S':
	 if (oldtry++ > MAXTRY) return('A');
	 if (num == ((n==0) ? 63:n-1)) {
	    spar(msgpkt);
	    spack('Y',num,9,msgpkt);
	    numtry = 0;
	    return(state);
	    }
	 else return('A');
      case 'Z':
	 if (oldtry++ > MAXTRY) return('A');
	 if (num == ((n==0) ? 63:n-1)) {
	    spack('Y',num,0,"");
	    ScrollInfoMsg(1);
	    numtry = 0;
	    return(state);
	    }
	 else return('A');
      case 'F':
	if (num != n) return('A');
	if(!first_time) {	/* Scroll the Z packet line up */
	    dostats('Z', "DONE");
	    ScrollInfoMsg(1);
	}
	buf = msgpkt;
	fileptr = filnam;
	while ((a = *buf++) != '\0') { /* Terminator added by rpack() */
	    if (rptflg) {
		if (a == rptq) {
		    rpt = unchar(*buf++);
		    a = *buf++;
		}
	    }
	    b8 = 0;
	    if (ebqflg) {		/* 8th-bit prefixing? */
		if (a == ebq) {		/* Yes, got an 8th-bit prefix? */
		    b8 = 0200;		/* Yes, remember this, */
		    a = *buf++;		/* and get the prefixed character. */
		}
	    }
	    if (a == quote) {
		a  = *buf++;
		a7 = a & 0177;
		if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') a = ctl(a);
	    }
	    a |= b8;
	    if (rpt == 0) rpt = 1;
	    if (p_mode == 1 && a == '\r') continue;
	    for (; rpt > 0; rpt--) *fileptr++ = a;
	    *fileptr = '\0';	/* Terminate the filename */
	}

	if (p_convert) {
	    char *p;
	    p = &filnam[0];
	    while (*p) { *p = tolower(*p); p++; }
	}
	if (notfirst) {
	    totbytes = 0L;
	    dostats('F',"RECV");
	}
	/* is the first file so emit actual file name from host */
	else {
	    notfirst++;
	}
	if ((fp = fopen(filnam,"w")) == NULL) {
	    InfoMsg2Line("KERMIT: Unable to create file:", filnam);
	    strcpy(msgpkt,"VT100 - Kermit - cannot create file: ");
	    strcat(msgpkt,filnam);
	    spack('E',n,strlen(msgpkt),msgpkt); /* let host know */
	    dostats('E',"ERROR");
	    return ('\0');	 /* abort everything */
	}
	spack('Y',n,0,"");
	oldtry = numtry;
	numtry = 0;
	retry--;
	n = (n+1)%64;
	return('D');

      /* totaly done server sending no more */
      case 'B':
	if (num != n) return ('A');
	spack('Y',n,0,"");
   	dostats('B', "DONE");
	ScrollInfoMsg(1);
	retry--;
	return('C');
      case 'E':
	return('E');
      case FALSE:
	if (timeout == USERABORT) return('A');
	spack('N',n,0,"");
	return(state);
      default:
	return ('A');
      }
   }

char rdata()
   {
   int num, len;
   retry++;
   if (numtry++ > MAXTRY) return('A');

   switch(rpack(&len,&num,msgpkt)) {
      case 'D':
	 if (num != n) {
	    if (oldtry++ > MAXTRY) return('A');
	    if (num == ((n==0) ? 63:n-1)) {
	       spack('Y',num,6,msgpkt);
	       numtry = 0;
	       return(state);
	       }
	    else return('A');
	    }
	 decode();
	 spack('Y',n,0,"");
	 oldtry = numtry;
	 numtry = 0;
	 retry--;
	 n = (n+1)%64;
	 return('D');
      case 'Z':
	 if (num != n) return('A');
	 spack('Y',n,0,"");
	 n = (n+1)%64;
	 dostats('Z',"DONE");
	 retry--;
	 fclose(fp);
	 return('Z');
      case 'F':
	 if (oldtry++ > MAXTRY) return('A');
	 if (num == ((n==0) ? 63:n-1)) {
	     spack('Y',num,0,"");
	     numtry = 0;
	     return(state);
	     }
      case 'E':
	 return('E');
      case FALSE:
	 if (timeout == USERABORT) return('A');
	 spack('N',n,0,"");
	 return(state);
      default:
	return('A');
      }
   }


spack(type,num,len,data)
char type, *data;
int num, len;
   {
   int i;
   char chksum, buffer[100];
   register char *bufp;

   if(sending && (lastpkt != num)) {
	tp++;
	lastpkt = num;
   }
   dostats(type,mainmode);
   bufp = buffer;
   ClearBuffer();
   for (i=1; i<=pad; i++) sendchar(padchar);

   *bufp++ = SOH;
   *bufp++ = tochar(len+3);
   chksum  = tochar(len+3);
   *bufp++ = tochar(num);
   chksum += tochar(num);
   *bufp++ = type;
   chksum += type;

   for (i=0; i<len; i++) {
      *bufp++ = data[i];
      chksum += data[i];
      }
   chksum = (((chksum&0300) >> 6)+chksum)&077;
   *bufp++ = tochar(chksum);
   if (eol)
	*bufp++ = eol; /* Use sender's requested end-of-line */
   if (eol != '\r')
	*bufp++ = '\r';
   *bufp++ = '\n';
   *bufp   = '\0';
   sendstring(buffer);
   }

rpack(len,num,data)
int *len, *num;
char *data;
   {
   int i, done;
   char type, cchksum, rchksum;
   char t = '\0';

    do {
       t = readchar();
       if (timeout != GOODREAD) return(FALSE);
       } while (t != SOH);

    done = FALSE;
    while (!done) {
       t = readchar();
       if (timeout != GOODREAD) return(FALSE);
       if (t == SOH) continue;
       cchksum = t;
       *len = unchar(t)-3;
       t = readchar();
       if (timeout != GOODREAD) return(FALSE);
       if (t == SOH) continue;
       cchksum = cchksum + t;
       *num = unchar(t);
       t = readchar();
       if (timeout != GOODREAD) return(FALSE);
       if (t == SOH) continue;
       cchksum = cchksum + t;
       type = t;
       for (i=0; i<*len; i++) {
	  t = readchar();
	  if (timeout != GOODREAD) return(FALSE);
	  if (t == SOH) continue;
	  cchksum = cchksum + t;
	  data[i] = t;
	  }
       data[*len] = 0;
       t = readchar();
       if (timeout != GOODREAD) return(FALSE);
       rchksum = unchar(t);
       t = readchar();
       if (timeout != GOODREAD) return(FALSE);
       if (t == SOH) continue;
       done = TRUE;
       }
   if(type != 'B' && type != 'Z')
	dostats(type,mainmode);
   cchksum = (((cchksum&0300) >> 6)+cchksum)&077;
   if (cchksum != rchksum) return(FALSE);
   if(!sending && (*num != lastpkt)) {
   	tp++;
   	lastpkt = *num;
   }
   return((int)type);
   }

getpkt() {
   int i,eof;

   static char leftover[10] = { '\0', '\0', '\0', '\0', '\0',
				'\0', '\0', '\0', '\0', '\0' };

   if (first == 1) {
      first = 0;
      *leftover = '\0';
      t = getc(fp);
      if (t == EOF) {
	 first = 1;
	 return(size = 0);
	 }
      totbytes++;
      }
   else if (first == -1) {
      first = 1;
      return(size = 0);
      }
   for (size = 0; (msgpkt[size] = leftover[size]) != '\0'; size++) ;
   *leftover = '\0';
   rpt = 0;
   eof = 0;
   while (!eof) {
      next = getc(fp);
      if (next == EOF) {
	 first = -1;
	 eof   =  1;
	 }
      else totbytes++;
      osize = size;
      encode(t);
      t = next;
      if (size == spsiz-3) return(size);
      if (size > spsiz-3) {
	 for (i = 0; (leftover[i] = msgpkt[osize+i]) != '\0'; i++) ;
	 size = osize;
	 msgpkt[size] = '\0';
	 return(size);
	 }
      }
   return(size);
   }

void encode(a)
char a;
   {
   int a7,b8;

   if (p_mode == 1 && a == '\n') {
      rpt = 0;
      msgpkt[size++] = quote;
      msgpkt[size++] = ctl('\r');
      if (size <= spsiz-3) osize = size;
      msgpkt[size++] = quote;
      msgpkt[size++] = ctl('\n');
      msgpkt[size]   = '\0';
      return;
      }
   if (rptflg) {
      if (a == next && (first == 0)) {
	 if (++rpt < 94) return;
	 else if (rpt == 94) {
	    msgpkt[size++] = rptq;
	    msgpkt[size++] = tochar(rpt);
	    rpt = 0;
	    }
	 }
      else if (rpt == 1) {
	 rpt = 0;
	 encode(a);
	 if (size <= spsiz-3) osize = size;
	 rpt = 0;
	 encode(a);
	 return;
	 }
      else if (rpt > 1) {
	 msgpkt[size++] = rptq;
	 msgpkt[size++] = tochar(++rpt);
	 rpt = 0;
	 }
      }
   a7 = a & 0177;
   b8 = a & 0200;

   if (ebqflg && b8) {			/* Do 8th bit prefix if necessary. */
	msgpkt[size++] = ebq;
	a = a7;
	}

   if ((a7 < SP) || (a7==DEL)) {
      msgpkt[size++] = quote;
      a = ctl(a);
      }
   if (a7 == quote) msgpkt[size++] = quote;
   if ((rptflg) && (a7 == rptq)) msgpkt[size++] = quote;

   if ((ebqflg) && (a7 == ebq)) /* Prefix the 8th bit prefix */
       msgpkt[size++] = quote;	/* if doing 8th-bit prefixes */

   msgpkt[size++] = a;
   msgpkt[size] = '\0';
   }

void decode()
   {
   USHORT  a, a7, b8;
   char *buf;

   buf = msgpkt;
   rpt = 0;

   while ((a = *buf++) != '\0') { /* Terminator added by rpack() */
      if (rptflg) {
	 if (a == rptq) {
	    rpt = unchar(*buf++);
	    a = *buf++;
	    }
	 }
      b8 = 0;
      if (ebqflg) {		     /* 8th-bit prefixing? */
	  if (a == ebq) {	     /* Yes, got an 8th-bit prefix? */
	      b8 = 0200;	     /* Yes, remember this, */
	      a = *buf++;	     /* and get the prefixed character. */
	  }
      }
      if (a == quote) {
	 a  = *buf++;
	 a7 = a & 0177;
	 if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') a = ctl(a);
	 }
      a |= b8;
      if (rpt == 0) rpt = 1;
      if (p_mode == 1 && a == '\r') continue;
      totbytes += rpt;
      for (; rpt > 0; rpt--) putc(a, fp);
      }
   return;
   }

void spar(data)
char data[];
   {
   data[0] = tochar(MAXPACKSIZ);
   data[1] = tochar(TTIME_KERMIT);
   data[2] = tochar(MYPAD);
   data[3] = ctl(MYPCHAR);
   data[4] = tochar(MYEOL);
   data[5] = MYQUOTE;
   if ((p_parity > 0) || ebqflg) {	   /* 8-bit quoting... */
	data[6] = MYEBQ;	  /* If parity or flag on, send &. */
	if ((ebq > 0040 && ebq < 0100) || /* If flag off, then turn it on  */
	   (ebq > 0140 && ebq < 0177) || /* if other side has asked us to */
	   (ebq == 'Y')) ebqflg = 1;
	}
    else				    /* Normally, */
       data[6] = 'Y';			    /* just say we're willing. */
    data[7] = '1';
    data[8] = MYRPTQ;
    data[9] = '\0';
    }

void rpar(data)
char data[];
    {
    spsiz   = unchar(data[0]);
    ttime   = unchar(data[1]);
    pad     = unchar(data[2]);
    padchar = ctl(data[3]);
    eol     = unchar(data[4]);
    quote   = data[5];
    rptflg  = 0;
    ebqflg  = 0;
    if (data[6] == 0) return;
    ebq = data[6];
    if ((ebq > 040 && ebq < 0100) ||
	(ebq > 0140 && ebq < 0177)) ebqflg = 1;
    else if (((p_parity > 0) || ebqflg) && (ebq == 'Y')) {
	ebqflg = 1;
	ebq = '&';
	}
    else ebqflg = 0;
    if (data[7] == 0) return;
    if (data[8] == 0) return;
    rptq    = data[8];
    rptflg  = ((rptq > 040 && rptq < 0100) ||
	(rptq > 0140 && rptq < 0177));
    }

saybye()
  {
  int len,num;
  if(numreqs != 0)	/* Requester's up... */
	Delay(5L);	/* ...so wait for Intuition, just in case. */
  spack('G',n,1,"F");  /* shut down server no more files */
  rpack(&len,&num,ackpkt);
  }

print_our_err()
    {
    if (retry > MAXTRY || oldtry > MAXTRY) {
	InfoMsg1Line("KERMIT: Too may retries for packet");
	strcpy(msgpkt,"VT100 KERMIT: Too many retries for packet");
	}
    else {
	InfoMsg1Line("KERMIT: Protocol Error");
	strcpy(msgpkt,"VT100 KERMIT: Protocol Error");
	}
    spack('E',n,strlen(msgpkt),msgpkt);
    }

print_host_err(msg)
  char *msg;
  {
  InfoMsg2Line("KERMIT: Host Error:", msg);
  }

dostats(type,stat)
char type,*stat;
    {
    char *statusform = "%5s %-15s Pkt: %4d Retr: %2d Bytes: %6ld Type: %c",
	 status[80];

    if (type == 'Y' || type == 'N' || type == 'G') return;

    sprintf(status, statusform, stat, filnam, tp, retry-1,
	    (LONG)totbytes, type);
    InfoMsgNoScroll(status);
}

ClearBuffer()
    {
    AbortIO(Read_Request);
    Wait(1L << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit);
    WaitIO(Read_Request);
    Read_Request->IOSer.io_Command = CMD_CLEAR;
    DoIO(Read_Request);
    Read_Request->IOSer.io_Command = CMD_READ;
    SendIO(Read_Request);
    }
SHAR_EOF
cat << \SHAR_EOF > remote.c
/****************************************************
 * vt100 emulator - remote character interpretation
 *
 *	v2.7 870227 ACS - No changes to this routine.
 *	v2.6 870227 DBW - bug fixes for all the stuff in v2.5
 *	v2.5 870214 DBW - more additions (see readme file)
 *	v2.4 861214 DBW - lots of fixes/additions (see readme file)
 *	v2.3 861101 DBW - minor bug fixes
 *	v2.2 861012 DBW - more of the same
 *	v2.1 860915 DBW - new features (see README)
 *	     860823 DBW - Integrated and rewrote lots of code
 *	v2.0 860803 DRB - Rewrote the control sequence parser
 *	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW	- First version released
 *
 ****************************************************/

#include "vt100.h"

static int    p[10];
static int    numpar;
static char   escseq[40];

/************************************************
*  function to handle remote characters
*************************************************/
void doremote(c)
char c;
    {
    if (c == 24) { inesc = 0; inctrl = 0; return; }
    if (c == 27 || (inesc >= 0 && c >= ' ')) { doesc(c); return; }
    if (inctrl >= 0 && c >= ' ') { doctrl(c); return; }
    if (c == 10 || c == 11 || c == 12) {
	if (nlmode) doindex('E'); else doindex('D');
	return;
	}
    if (c == 13) {
	if (!nlmode) emit(c);
	return;
	}
    if (c == 15) { alt = 0; return; }
    if (c == 14) { alt = 1; return; }
    if (a[alt] && c > 94 && c < 127) { doalt(c); return; }
    emit(c);
    }

void doesc(c)
char c;
{
    if (inesc < 0) { inesc = 0; return; }
    if (c == 27 || c == 24) { inesc = -1; return; }
    if (c < ' ' || c == 127) return;	  /* Ignore control chars */

    /* Collect intermediates */
    if (c < '0') {escseq[inesc++] = c; return; }

    /* by process of elimination, we have a final character.
       Put it in the buffer, and dispatch on the first character
       in the buffer */

    escseq[inesc] = c;
    inesc = -1;				/* No longer collecting a sequence */
    switch (escseq[0])			/* Dispatch on the first received */
    {
      case '[':				/* Control sequence introducer */
	numpar = 0;			/* No parameters yet */
	private = 0;			/* Not a private sequence (yet?) */
	badseq = 0;			/* Good until proven bad */
	p[0] = p[1] = 0;		/* But default the first parameter */
	inctrl = 0;			/* We are in a control sequence */
	return;				/* All done for now ... */

      case 'D': case 'E': case 'M':	/* Some kind of index */
	doindex (c);			/* Do the index */
	return;				/* Return */

      case '7':				/* Save cursor position */
	savx = x; savy = y; savmode = curmode; savalt = alt;
	sa[0] = a[0]; sa[1] = a[1];
	return;

      case '8':				/* Restore cursor position */
	x = savx; y = savy; alt = savalt; curmode = savmode;
	a[0] = sa[0]; a[1] = sa[1];
	return;

      case 'c':				/* Reset */
	top = MINY; bot = MAXY; savx = MINX; savy = MINY;
	curmode = FS_NORMAL; p_keyapp = 0; p_curapp = 0;
	inesc = -1;
	a[0] = 0; a[1] = 0; sa[0] = 0; sa[1] = 0;
	redoutil();
	emit(12);
	return;

      case '(':				/* Change character set */
	if (c == '0' || c == '2') a[0] = 1; else a[0] = 0;
	return;

      case ')':				/* Change the other character set */
	if (c == '0' || c == '2') a[1] = 1; else a[1] = 0;
	return;

      case '=':				/* set keypad application mode */
	p_keyapp = 1;
	redoutil();
	return;

      case '>':				/* reset application mode */
	p_keyapp = 0;
	redoutil();
	return;

      case 'Z':
	sendchar(27); sendstring("[?1;7c"); return;

      /* If we didn't match anything, we can just return, happy in the
	 knowledge that we've at least eaten the whole sequence */

    }					/* End of switch */
    return;
}

void doctrl(c)
char c;
{
    int	    i;

    if (c == 27 || c == 24) { inctrl = -1; return; }
    if (c < ' ' || c == 127) return;		  /* Ignore control chars */

    /* First, look for some parameter characters.  If the very first
	parameter character isn't a digit, then we have a
	private sequence */

    if (c >= '0' && c < '@')
    {
	/* can't have parameters after intermediates */
	if (inctrl > 0) {badseq++ ; return; }
	switch (c)
	{
	  case '0': case '1': case '2': case '3': case '4':
	  case '5': case '6': case '7': case '8': case '9':
	    p[numpar] = p[numpar] * 10 + (c - '0');
	    return;

	  case ';':
	    p[++numpar] = 0;		/* Start a new parameter */
	    return;

	  case '<': case '=': case '>': case '?': /* Can only mean private */

	    /* Only allowed BEFORE parameters */
	    if (inctrl == 0) private = c;
	    return;

	/* if we come here, it's a bad sequence */
	}
	badseq++;			/* Flag the bad sequence */
    }

    if (c < '0')			/* Intermediate character */
    {
	escseq[inctrl++] = c;		/* Save the intermediate character */
	return;
    }

    /* if we get here, we have the final character.  Put it in the
       escape sequence buffer, then dispatch the control sequence */

    numpar++;				/* Reflect the real number of parameters */
    escseq[inctrl++] = c;		/* Store the final character */
    escseq[inctrl] = '\000';		/* Tie off the buffer */
    inctrl = -1;			/* End of the control sequence scan */

    /* Don't know how to do most private sequences right now,
	so just punt them */

    if ((private != 0 && private != '?') || badseq != 0) return;
    if (private == '?' && escseq[0] != 'h' &&
	escseq[0] != 'l') return;

    switch (escseq[0])			/* Dispatch on first intermediate or final */
    {
      case 'A': if (p[0]<=0) p[0] = 1;
		y -= 8*p[0]; if (y<top)  y = top;  return;
      case 'B': if (p[0]<=0) p[0] = 1;
		y += 8*p[0]; if (y>bot)  y = bot;  return;
      case 'C': if (p[0]<=0) p[0] = 1;
		x += 8*p[0]; if (x>MAXX) x = MAXX; return;
      case 'D': if (p[0]<=0) p[0] = 1;
		x -= 8*p[0]; if (x<MINX) x = MINX; return;

      case 'H': case 'f':		/* Cursor position */
	if (p[0] <= 0) p[0] = 1;
	if (p[1] <= 0) p[1] = 1;
	y = (--p[0]*8)+MINY; x = (--p[1]*8)+MINX;
	if (y > MAXY) y = MAXY;
	if (x > MAXX) x = MAXX;
	if (y < MINY) y = MINY;
	if (x < MINX) x = MINX;
	return;

      case 'L':				/* ANSI insert line */
      case 'M':				/* ANSI delete line */
	if (p[0] <= 0) p[0] = 1;
	ScrollRaster(mywindow->RPort,0L,
	    (long)((escseq[0] == 'M' ? 8L : -8L) * p[0]),
	    (long)MINX,(long)y-6,(long)(MAXX+7),(long)bot+1);
	return;

      case 'r':				/* Set scroll region */
	if (p[0] <= 0) p[0] = 1;
	if (p[1] <= 0) p[1] = p_lines;
	top = (--p[0]*8)+MINY; bot = (--p[1]*8)+MINY;
	if (top < MINY) top = MINY;
	if (bot > MAXY) bot = MAXY;
	if (top > bot) { top = MINY; bot = MAXY; }
	x = MINX; y = MINY;
	return;

      case 'm':				/* Set graphic rendition */
	for (i=0;i<numpar;i++) {
	    if (p[i] < 0) p[i] = 0;
	    switch (p[i]) {
		case 0:
		curmode  = FS_NORMAL;
		break;

		case 1:
		curmode |= FSF_BOLD;
		break;

		case 4:
		curmode |= FSF_UNDERLINED;
		break;

		case 5:
		curmode |= FSF_ITALIC;
		break;

		default:
		curmode |= FSF_REVERSE;
		break;
		}
	    }
	return;

      case 'K':				/* Erase in line */
	doerase();
	return;

      case 'J':				/* Erase in display */
	if (p[0] < 0) p[0] = 0;
	SetAPen(mywindow->RPort,0L);
	if (p[0] == 0) {
	    if (y < MAXY) RectFill(mywindow->RPort,
		(long)MINX,(long)(y+2),(long)(MAXX+7),(long)(MAXY+1));
	    }
	else if (p[0] == 1) {
	    if (y > MINY) RectFill(mywindow->RPort,
		(long)MINX,(long)(MINY-6),(long)(MAXX+7),(long)(y-7));
	    }
	else RectFill(mywindow->RPort,
	    (long)MINX,(long)(MINY-6),(long)(MAXX+7),(long)(MAXY+1));
	SetAPen(mywindow->RPort,1L);
	doerase(); return;

      case 'h':				/* Set parameter */
	if (private == 0 && p[0] == 20)		nlmode = 1;
	else if (private == '?') {
	    if      (p[0] == 7)	p_wrap   = 1;
	    else if (p[0] == 1)	p_curapp = 1;
	    redoutil();
	    }
	return;

      case 'l':				/* Reset parameter */
	if (private == 0 && p[0] == 20)		nlmode = 0;
	else if (private == '?') {
	    if      (p[0] == 7)	p_wrap   = 0;
	    else if (p[0] == 1) p_curapp = 0;
	    redoutil();
	    }
	return;

      case 'x':
	sendchar(27); sendstring("[3;1;8;64;64;1;0x"); return;

      case 'n':
	if (p[0] == 6) {
	    sendchar(27);
	    sprintf(escseq,"[%d;%dR",((y-MINY)/8)+1,((x-MINX)/8)+1);
	    sendstring(escseq); return;
	    }
	sendchar(27); sendstring("[0n"); return;

      case 'c':
	sendchar(27); sendstring("[?1;7c"); return;
    }

    /* Don't know how to do this one, so punt it */
}

void doindex(c)
char c;
    {
    if (c != 'M') {
	if (c == 'E') x = MINX;
	if (y > bot) if (y < MAXY) y += 8;
	if (y == bot)
	    ScrollRaster(mywindow->RPort,0L,8L,(long)MINX,(long)(top-6),
		(long)(MAXX+7),(long)(bot+1));
	if (y < bot) y += 8;
	}
    else {
	if (y < top) if (y > MINY) y -= 8;
	if (y == top)
	    ScrollRaster(mywindow->RPort,0L,-8L,(long)MINX,(long)(top-6),
		(long)(MAXX+7),(long)(bot+1));
	if (y > top) y -= 8;
	}
    return;
    }

doalt(c)
char c;
    {
    int oldx,newx;
    inesc = -1;
    oldx = x; emit(' '); newx = x;
    x = oldx;
    SetAPen(mywindow->RPort,1L);
    switch (c) {
	case 'a':
	doline(0,-6,8,1);
	break;

	case 'j':
	case 'm':
	case 'v':   doline(4,-6,4,-2);
	if      (c=='j')  doline(0,-2,4,-2);
	else if (c=='m')  doline(4,-2,8,-2);
	else              doline(0,-2,8,-2);
	break;

	case 'k':
	case 'l':
	case 'w': doline(4,-2,4,1);
	if      (c=='k')  doline(0,-2,4,-2);
	else if (c=='l')  doline(4,-2,8,-2);
	else              doline(0,-2,8,-2);
	break;

	case 'n':
	case 'q': doline(0,-2,8,-2);
	if      (c=='n')  doline(4,-6,4,2);
	break;

	case 't':
	case 'u':
	case 'x':   doline(4,-6,4,1);
	if      (c=='t')  doline(4,-2,8,-2);
	else if (c=='u')  doline(0,-2,4,-2);
	break;
	}
    x = newx;
    }

doline(x1,y1,x2,y2) {
    RectFill(mywindow->RPort,(long)(x+x1),(long)(y+y1),
	(long)(x+x2),(long)(y+y2));
    }

void doerase()
    {
    if (p[0] < 0) p[0] = 0;
    SetAPen(mywindow->RPort,0L);
    if (p[0] == 0) RectFill(mywindow->RPort,(long)x,(long)(y-6),
	(long)(MAXX+7),(long)(y+1));
    else if (p[0] == 1) RectFill(mywindow->RPort,
	(long)MINX,(long)(y-6),(long)(x+7),(long)(y+1));
    else RectFill(mywindow->RPort,
	(long)MINX,(long)(y-6),(long)(MAXX+7),(long)(y+1));
    SetAPen(mywindow->RPort,1L);
    return;
    }

SHAR_EOF