🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: mod.amiga.sources
Article #32

New VT100 (part 2 of 2)

#32
From: doc
Date: Wed, 03 Sep 1986 06:53
2095 lines
57019 bytes
#	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
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	init.c
#	kermit.c
#	remote.c
#	script.c
# This archive created: Wed Sep  3 01:51:08 1986
# By:	Craig Norborg (Purdue University Computing Center)
cat << \SHAR_EOF > init.c
/***************************************************************
 * vt100 - terminal emulator - initialization
 *
 *	     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
 *
 ***************************************************************/

#define MODULE_INIT 1
#include "vt100.h"

extern char *malloc();

void InitDefaults(argc,argv)
int	argc;
char	**argv;
    {
    FILE    *fd;
    char    line[256],scr[32],delim,macro[256],c0,*ptr;
    int	    i,j,k;

    if (((argc > 1) && (fd=fopen(argv[1],"r")) != 0) ||
	(fd=fopen("vt100.init","r")) != 0 ||
	(fd=fopen("c:vt100.init","r")) != 0) {
	while (fgets(line,256,fd) != 0) {
	    if ((c0 = line[0]) == '#') continue;
	    if ((c0|' ') == 'e') break;
	    switch (c0|' ') {
		case 'b':
		if ((line[1]|' ') == 'o') {
		    /* bold color */
		    if (sscanf(line,"%s %x",scr,&i) == 2) p_bold = i;
		    break;
		    }
		if ((line[1]|' ') != 'a') break;
		switch(line[2]|' ') {
		    /* baud rate */
		    case 'u':
		    if (sscanf(line,"%s %d",scr,&i) == 2) p_baud = i;
		    break;

		    /* background */
		    case 'c':
		    if (sscanf(line,"%s %x",scr,&i) == 2) p_background = i;
		    break;
		    }
		break;

		/* screen type */
		case 's':
		if (sscanf(line,"%s %s",scr,scr) == 2) {
		    if ((scr[0]|' ') == 'w') p_screen = 0;
		    else		     p_screen = 1;
		    }
		break;

		/* number of lines */
		case 'l':
		if (sscanf(line,"%s %d",scr,&i) == 2) p_lines = i;
		break;

		/* screen depth */
		case 'd':
		if (sscanf(line,"%s %d",scr,&i) == 2) p_depth = i;
		break;

		/* cursor color */
		case 'c':
		if (sscanf(line,"%s %d",scr,&i) == 2) p_cursor = i;
		break;

		/* interlace type */
		case 'i':
		if (sscanf(line,"%s %s",scr,scr) == 2) {
		    if ((scr[1]|' ') == 'n') p_interlace = 1;
		    else		     p_interlace = 0;
		    }
		break;

		case 'f':
		switch (line[1]|' ') {

		    /* foreground color */
		    case 'o':
    		    if (sscanf(line,"%s %x",scr,&i) == 2) p_foreground = i;
		    break;

		    /* function key */
		    default:
		    if (sscanf(&line[1],"%d",&i) != 1) break;
		    if (i < 1 || i > 10) break;
		    delim = 0;
		    for (j=2; line[j] != 0 &&
			      (line[j] == ' ' || line[j] == '\t'); j++) ;
		    if (line[j] == 0) {
			if (c0 == 'f') p_f[i-1] = NULL;
			else	       p_F[i-1] = NULL;
			break;
			}
		    delim = line[j];
		    k = 0;
		    macro[0] = 0;
		    while (line[++j] != delim) {
			if (line[j] == 0) {
			    if (fgets(line,256,fd) == 0) {
				line[0] = delim;
				line[1] = 0;
				}
			    j = -1;
			    continue;
			    }
			if (line[j] == '^' && line[++j] != '^')
			    macro[k++] = (line[j]|' ') - 0x60;
			else if (line[j] != '\n') macro[k++] = line[j];
			macro[k]   = 0;
			}
		    ptr = malloc(k+1);
		    if (c0 == 'f') p_f[i-1] = ptr;
		    else	   p_F[i-1] = ptr;
		    strcpy(ptr,macro);
		    break;
		    }
		break;

		case 'm':
		if (sscanf(line,"%s %s",scr,scr) == 2) {
		    if ((scr[0]|' ') == 'i')	p_mode = 0;
		    else			p_mode = 1;
		    }
		break;

		case 'x':
		if (sscanf(line,"%s %s",scr,scr) == 2) {
		    if ((scr[0]|' ') == 'd')	p_xon = 0;
		    else			p_xon = 1;
		    }
		break;
		}
	    }
	fclose(fd);
	}
    /* 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   = 3L;
    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)+15);
	if (p_interlace == 1)
	    NewScreen.TopEdge   = (long)(402 - NewScreen.Height);
	else
	    NewScreen.TopEdge   = 0L;
	}
    else {
	p_depth			= 2L;
	NewWindow.TopEdge	= 0L;
	NewWindow.Screen	= NULL;
	NewWindow.Type	= WBENCHSCREEN;
	}
    }

void InitDevs()
{
USHORT	colors[4];

IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", INTUITION_REV);
if( IntuitionBase == NULL )
   {
   puts("can't open intuition\n");
   exit(TRUE);
   }

GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",GRAPHICS_REV);
if( GfxBase == NULL )
   {
   puts("can't open graphics library\n");
   exit(TRUE);
   }

if (p_screen == 1) {
    if ((myscreen = (struct Screen *)OpenScreen(&NewScreen)) == NULL) {
	puts("can't open screen!!\n");
	exit(TRUE);
	}
    NewWindow.Screen = myscreen;
    }

if(( mywindow = (struct Window *)OpenWindow(&NewWindow) ) == NULL)
   {
   puts("cant open window\n");
   if (p_screen != 0) CloseScreen( myscreen );
   exit(TRUE);
   }

myviewport   = (struct ViewPort *)ViewPortAddress(mywindow);

if (p_screen != 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 = SERF_SHARED | SERF_XDISABLED;
Read_Request->IOSer.io_Message.mn_ReplyPort = CreatePort("Read_RS",0);
if(OpenDevice(SERIALNAME,NULL,Read_Request,NULL))
   {
   puts("Cant open Read device\n");
   CloseWindow( mywindow );
   if (p_screen != 0) CloseScreen( myscreen );
   DeletePort(Read_Request->IOSer.io_Message.mn_ReplyPort);
   FreeMem(Read_Request,(long)sizeof(*Read_Request));
   exit(TRUE);
   }
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);
Write_Request->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
Write_Request->IOSer.io_Message.mn_ReplyPort = CreatePort("Write_RS",0);
if(OpenDevice(SERIALNAME,NULL,Write_Request,NULL))
    {
    puts("Cant open Write device\n");
    CloseDevice(Read_Request);
    DeletePort(Read_Request->IOSer.io_Message.mn_ReplyPort);
    FreeMem(Read_Request,(long)sizeof(*Read_Request));
    DeletePort(Write_Request->IOSer.io_Message.mn_ReplyPort);
    FreeMem(Write_Request,(long)sizeof(*Write_Request));
    CloseWindow( mywindow );
    if (p_screen != 0) CloseScreen( myscreen );
    exit(TRUE);
    }
Write_Request->IOSer.io_Command = CMD_WRITE;
Write_Request->IOSer.io_Length = 1;
Write_Request->IOSer.io_Data = (APTR) &rs_out[0];

Read_Request->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
Read_Request->io_Baud = p_baud;
Read_Request->io_ReadLen = 8;
Read_Request->io_WriteLen = 8;
Read_Request->io_CtlChar = 1L;
Read_Request->io_RBufLen = 2048;
Read_Request->IOSer.io_Command = SDCMD_SETPARAMS;
DoIO(Read_Request);
Read_Request->IOSer.io_Command = CMD_READ;

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

if (OpenDevice(TIMERNAME, UNIT_VBLANK, (char *) &Timer, 0) ||
    OpenDevice(TIMERNAME, UNIT_VBLANK, (char *) &Script_Timer, 0)) {
    puts("can't open timer device");
    DeletePort(Timer_Port);
    DeletePort(Script_Timer_Port);
    CloseDevice(Read_Request);
    DeletePort(Read_Request->IOSer.io_Message.mn_ReplyPort);
    FreeMem(Read_Request,(long)sizeof(*Read_Request));
    CloseDevice(Write_Request);
    DeletePort(Write_Request->IOSer.io_Message.mn_ReplyPort);
    FreeMem(Write_Request,(long)sizeof(*Write_Request));
    CloseWindow( mywindow );
    if (p_screen != 0) CloseScreen( myscreen );
    exit(TRUE);
    }

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;
}

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

/* initialize each menu item and IntuiText with loop */
for( n=0; n<FILEMAX; n++ )
   {
   FileItem[n].NextItem = &FileItem[n+1];
   FileItem[n].LeftEdge = 0;
   FileItem[n].TopEdge = 11 * n;
   FileItem[n].Width = 135;
   FileItem[n].Height = 11;
   FileItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX;
   FileItem[n].MutualExclude = 0;
   FileItem[n].ItemFill = (APTR)&FileText[n];
   FileItem[n].SelectFill = NULL;
   FileItem[n].Command = 0;
   FileItem[n].SubItem = NULL;
   FileItem[n].NextSelect = 0;

   FileText[n].FrontPen = 0;
   FileText[n].BackPen = 1;
   FileText[n].DrawMode = JAM2;     /* render in fore and background */
   FileText[n].LeftEdge = 0;
   FileText[n].TopEdge = 1;
   FileText[n].ITextFont = NULL;
   FileText[n].NextText = NULL;
   }
FileItem[FILEMAX-1].NextItem = NULL;

/* initialize text for specific menu items */
FileText[0].IText = (UBYTE *)"Ascii Capture";
FileText[1].IText = (UBYTE *)"Ascii Send";
FileText[2].IText = (UBYTE *)"Xmodem Receive";
FileText[3].IText = (UBYTE *)"Xmodem Send";
FileText[4].IText = (UBYTE *)"Kermit Get";
FileText[5].IText = (UBYTE *)"Kermit Receive";
FileText[6].IText = (UBYTE *)"Kermit Send";
FileText[7].IText = (UBYTE *)"Kermit BYE";
}

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

/* initialize each menu item and IntuiText with loop */
for( n=0; n<RSMAX; n++ )
   {
   RSItem[n].NextItem = &RSItem[n+1];
   RSItem[n].LeftEdge = 0;
   RSItem[n].TopEdge = 11 * n;
   RSItem[n].Width = 85;
   RSItem[n].Height = 11;
   RSItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX | CHECKIT;
   RSItem[n].MutualExclude = (~(1 << n));
   RSItem[n].ItemFill = (APTR)&RSText[n];
   RSItem[n].SelectFill = NULL;
   RSItem[n].Command = 0;
   RSItem[n].SubItem = NULL;
   RSItem[n].NextSelect = 0;

   RSText[n].FrontPen = 0;
   RSText[n].BackPen = 1;
   RSText[n].DrawMode = JAM2;     /* render in fore and background */
   RSText[n].LeftEdge = 0;
   RSText[n].TopEdge = 1;
   RSText[n].ITextFont = NULL;
   RSText[n].NextText = NULL;
   }
RSItem[RSMAX-1].NextItem = NULL;
/* 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 = ITEMTEXT | ITEMENABLED | HIGHBOX | CHECKIT | CHECKED;

/* initialize text for specific menu items */
RSText[0].IText = (UBYTE *)"   300";
RSText[1].IText = (UBYTE *)"   1200";
RSText[2].IText = (UBYTE *)"   2400";
RSText[3].IText = (UBYTE *)"   4800";
RSText[4].IText = (UBYTE *)"   9600";
}

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

/* initialize each menu item and IntuiText with loop */
for( n=0; n<XFMAX; n++ )
   {
   XFItem[n].NextItem = &XFItem[n+1];
   XFItem[n].LeftEdge = 0;
   XFItem[n].TopEdge = 11 * n;
   XFItem[n].Width = 85;
   XFItem[n].Height = 11;
   XFItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX | CHECKIT;
   XFItem[n].MutualExclude = (~(1 << n));
   XFItem[n].ItemFill = (APTR)&XFText[n];
   XFItem[n].SelectFill = NULL;
   XFItem[n].Command = 0;
   XFItem[n].SubItem = NULL;
   XFItem[n].NextSelect = 0;

   XFText[n].FrontPen = 0;
   XFText[n].BackPen = 1;
   XFText[n].DrawMode = JAM2;     /* render in fore and background */
   XFText[n].LeftEdge = 0;
   XFText[n].TopEdge = 1;
   XFText[n].ITextFont = NULL;
   XFText[n].NextText = NULL;
   }
XFItem[XFMAX-1].NextItem = NULL;
/* mode checked */
XFItem[p_mode].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX | CHECKIT | CHECKED;

/* initialize text for specific menu items */
XFText[0].IText = (UBYTE *)"  image";
XFText[1].IText = (UBYTE *)"  CR LF";
}


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

/* initialize each menu item and IntuiText with loop */
for( n=0; n<SCRIPTMAX; n++ )
   {
   ScriptItem[n].NextItem = &ScriptItem[n+1];
   ScriptItem[n].LeftEdge = 0;
   ScriptItem[n].TopEdge = 11 * n;
   ScriptItem[n].Width = 155;
   ScriptItem[n].Height = 11;
   ScriptItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX;
   ScriptItem[n].MutualExclude = 0;
   ScriptItem[n].ItemFill = (APTR)&ScriptText[n];
   ScriptItem[n].SelectFill = NULL;
   ScriptItem[n].Command = 0;
   ScriptItem[n].SubItem = NULL;
   ScriptItem[n].NextSelect = 0;

   ScriptText[n].FrontPen = 0;
   ScriptText[n].BackPen = 1;
   ScriptText[n].DrawMode = JAM2;     /* render in fore and background */
   ScriptText[n].LeftEdge = 0;
   ScriptText[n].TopEdge = 1;
   ScriptText[n].ITextFont = NULL;
   ScriptText[n].NextText = NULL;
   }
ScriptItem[SCRIPTMAX-1].NextItem = NULL;

/* initialize text for specific menu items */
ScriptText[0].IText = (UBYTE *)"Execute file";
ScriptText[1].IText = (UBYTE *)"Abort Execution";
}

/**********************************************************************/
/*   The following function initializes the Menu structure array with */
/*  appropriate values for our simple menu strip.  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 = 50;
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 = 65;
menu[1].TopEdge = 0;
menu[1].Width = 85;
menu[1].Height = 10;
menu[1].Flags = MENUENABLED;
menu[1].MenuName = "BaudRate";        /* text for menu-bar display */
menu[1].FirstItem = &RSItem[0];    /* pointer to first item in list */

menu[2].NextMenu = &menu[3];
menu[2].LeftEdge = 160;
menu[2].TopEdge = 0;
menu[2].Width = 85;
menu[2].Height = 10;
menu[2].Flags = MENUENABLED;
menu[2].MenuName = "Xfer Mode";        /* text for menu-bar display */
menu[2].FirstItem = &XFItem[0];    /* pointer to first item in list */

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

SHAR_EOF
cat << \SHAR_EOF > kermit.c
/*************************************************************
 * vt100 terminal emulator - KERMIT protocol support
 *           
 *	     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
 *
 *************************************************************/

#define MODULE_KERMIT 1
#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 MYPAD      0       /* Number of padding characters 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
   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 */
   rptflg,    /* are we doing repeat quoting */
   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 */
   ackpkt[MAXPACKSIZ+20], /* ACK/NAK packet buffer */
   msgpkt[MAXPACKSIZ+20], /* Message Packet buffer */
   filnam[40];            /* remote file name */
   snum[10];

void encode(), decode(), rpar(), spar();
   
FILE *fp;     /* file for send/receive */

int shutdown = 0;  /* shut down server after all xfers complete */

char *
getfname(name)   /* returns pointer to start of file name from file 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 retval;

   ttime = TTIME_LONG;
   if (!strcmp(file,"$")) { saybye(); return(2); }
   if (file[strlen(file)-1] == '$')  { 
             shutdown = 1; 
             file[strlen(file)-1] = '\0'; 
             }
   if ((fp = fopen(file,"r")) == NULL) {
      emits("Cannot open send file\n");
      return FALSE;
      }
   getready(file,more);
   emits("SEND");
   retval  = sendsw();
   if (retval) { x = 600; emits("DONE"); }
   curmode = 0;
   if (shutdown) saybye();
   emits("\n");
   fclose(fp);
   return(retval);
   }
 
dokreceive(file,more)
char *file;
int more;
   {
   int retval;

   ttime = TTIME_LONG;
   if (!strcmp(file,"$")) { saybye(); return(2); }
   if (file[strlen(file)-1] == '$')  { 
             shutdown = 1; 
             file[strlen(file)-1] = '\0'; 
             }
   if ((fp = fopen(file,"w")) == NULL) {
      emits("Cannot open file\n");
      return FALSE;
      }
   getready(file,more);
   emits("RECV");
   retval  = recsw();
   if (retval) { x = 600; emits("DONE"); }
   curmode = 0;
   if (shutdown) saybye();
   emits("\n");
   fclose(fp);
   return(retval);
   }

getready(file,more)
   char *file;
   int more;
   {
   if (!more) {   
       emits("Remote file name [");
       emits(getfname(file));
       emits("]: ");
       filename(filnam);
       if (filnam[0] == 0) strcpy(filnam,getfname(file));
       emits("Type <ESC> to abort transfer\n");
       }
   else strcpy(filnam,getfname(file));
   eatup();
   tp =  retry =  0; totbytes = 0L;  n =  numtry = 0;
   want_message = FALSE; /* tell readchar no error msgs status bar instead */
   statusline();
   x = 600;
   }


sendsw()
   {
   char sinit(), sfile(), sdata(), seof(), sbreak();

   state = 'S';
   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':   state = sbreak(); break;
         case 'C':   return(TRUE);
         case 'A':   x = 600;
                     if (timeout == USERABORT) { sabort();  return(FALSE); }
                     if (timeout == TIMEOUT) emits("TMOUT");
                     else emits("ERROR");
                     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 = '#';
                 numtry = 0;
                 retry--;
                 n = (n+1)%64;
                 return('F');
      case 'E':  return('A');
      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('A');
      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('A');
      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) { 
        timeout = GOODREAD;
        spack('Z',n,1,"D"); /* tell host to discard file */
        }
   else spack('Z',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);
         numtry = 0;
         retry--;
         n = (n+1)%64;
         return('B');
      case 'E':
         return('A');
      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);
         numtry = 0;
	 retry--;
         n = (n+1)%64;
         return('C');
      case 'E':
         return('A');
      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()
   {
   emits("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(), rbreak();

   state = 'R';
   
   while(TRUE) {
      switch(state) {
         case 'R':   state = rinit(); break;
         case 'F':   state = rfile(); break;
         case 'D':   state = rdata(); break;
	 case 'Z':   state = rbreak(); break;
         case 'C':   return(TRUE);
         case 'A':   x = 600;
                     if (timeout == USERABORT){/* 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.           */
                         emits("ABORT");
                         spack('E',n,0,0); /* send an error packet back   */
                     }
                     else if (timeout == TIMEOUT) emits("TMOUT");
                     else emits("ERROR");           
                     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,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('A');
      case FALSE:
         if (timeout == USERABORT) return('A');
         spack('N',n,0,0);
         return(state);
      default:
         return('A');
      }
   }

char rfile()
   {
   int num, len;
   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);
            retry--;
            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,0);
            numtry = 0;
            retry--;
            return(state);
            }
         else return('A');
      case 'F':
         if (num != n) return('A');
         spack('Y',n,0,0);
         oldtry = numtry;
         numtry = 0;
         retry--;
         n = (n+1)%64;
         return('D');
      case 'B':
         if (num != n) return ('A');
         spack('Y',n,0,0);
         retry--;
         return('C');
      case 'E':
         return('A');
      case FALSE:
         if (timeout == USERABORT) return('A');
         spack('N',n,0,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);
               retry--;
               numtry = 0;
               return(state);
               }
            else return('A');
            }
         decode();
         spack('Y',n,0,0);
         oldtry = numtry;
         numtry = 0;
         retry--;
         n = (n+1)%64;
         return('D');
      case 'F':
         if (oldtry++ > MAXTRY) return('A');
         if (num == ((n==0) ? 63:n-1)) {
            spack('Y',num,0,0);
            numtry = 0;
            retry--;
            return(state);
            }
         else return('A');
      case 'Z':
         if (num != n) return('A');
         spack('Y',n,0,0);
         n = (n+1)%64;
         retry--;
         return('Z');
      case 'E':
         return('A');
      case FALSE:
         if (timeout == USERABORT) return('A');
         spack('N',n,0,0);
         return(state);
      default:
        return('A');
      }
   }

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

   switch(rpack(&len,&num,msgpkt)) {
      case 'B':
         spack('Y',n,0,0);
         return('C');
      case 'Z':
         spack('Y',n,0,0);
         return('Z');
      case 'E':
         return('A');
      case FALSE:
         spack('N',n,0,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;
   
   dostats(type);
   bufp = buffer;
   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);
   *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;
       }
   dostats(type);
   cchksum = (((cchksum&0300) >> 6)+cchksum)&077;
   if (cchksum != rchksum) return(FALSE);
   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 ((a7 < SP) || (a7==DEL)) {
      msgpkt[size++] = quote;
      a = ctl(a);
      }
   if (a7 == quote) msgpkt[size++] = quote;
   if ((rptflg) && (a7 == rptq)) msgpkt[size++] = quote;
   msgpkt[size++] = a;
   msgpkt[size] = '\0';
   }

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

   buf = msgpkt;
   rpt = 0;
   
   while ((a = *buf++) != '\0') {
      if (rptflg) {
         if (a == rptq) {
            rpt = unchar(*buf++);
            a = *buf++;
            }
         }
      if (a == quote) {
         a  = *buf++;
         a7 = a & 0177;
         if ((a7 >= 0100 && a7 <= 0137) || a7 == '?') a = ctl(a);
         }
      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_LONG);
   data[2] = tochar(MYPAD);
   data[3] = ctl(MYPCHAR);
   data[4] = tochar(MYEOL);
   data[5] = MYQUOTE;
   data[6] = 'N';
   data[7] = '1';
   data[8] = MYRPTQ;
   data[9] = '\0';
   }

void rpar(data)
char data[];
   {
   spsiz   = unchar(data[0]);
   timint  = unchar(data[1]);
   pad     = unchar(data[2]);
   padchar = ctl(data[3]);
   eol     = unchar(data[4]);
   quote   = data[5];
   rptflg  = 0;
   if (data[6] == 0) return;
   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;
  shutdown = 0;
  spack('G',n,1,"F");  /* shut down server no more files */
  rpack(&len,&num,ackpkt);
  }

statusline()
  {
  emits ("\nFile:                 Pckt:   Pckt No:      Retrn:    Bytes:         Stat:      ");
  x = 48;
  curmode = 1;
  emits (filnam);
  return(0);
  }

dostats(type)
char type;
  {
   if (type != 'Y' && type != 'N' && type != 'G') {
      x = 224;
      emit(type);
      x = 312;
      sprintf(snum,"%4d",n+(tp * 64));
      emits(snum);
      if (n==63) tp++;
      x = 408;
      sprintf(snum,"%2d",retry-1);
      emits(snum);
      x = 488;
      sprintf(snum,"%6ld",(long)totbytes);
      emits(snum);
      }
  }

/* allow for multi file xfers separated by commas under kermit and XMODEM */

multi_xfer(name,mode,do_send)
char *name;
int (*mode)();
int do_send;
    {
    int done = 0;
    int status;
    char *p;
    
    p = name;  
    while(*p && *p != ',')   p++;
    if (*p == '\0') { 
         done = TRUE; 
         if (multi == 1) multi++;
         }
     else multi = 1;
    *p = '\0';
    status = ((*mode)(name, multi));
    if (status == TRUE) {
        if (do_send) emits("Sent File: ");
          else emits("Received File: ");
    	emits(name);
    	emits("\n");
    	emit(8);
        }
    else if (status == FALSE)
        {
        close(fd);
        if (do_send) emits("Send Failed: ");
          else emits("Receive Failed: ");
        emits(name);
        emits("\n");	
        emit(8);
        }    
    if (!done) multi_xfer(++p, mode, do_send);
    server = 0;
    multi = 0;
    }

/* gobble up all garb that we received while getting file name strings */

eatup()
   {
  while(CheckIO(Read_Request))  {
     	WaitIO(Read_Request);
     	BeginIO(Read_Request);
        }
   }   

SHAR_EOF
cat << \SHAR_EOF > remote.c
/****************************************************
 * vt100 emulator - remote character interpretation
 *
 *	     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
 *
 ****************************************************/

#define MODULE_REMOTE 1
#include "vt100.h"

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

void doctrl();
void doesc();				/* force correct denomination */
void doerase();
void doindex();

/************************************************
*  function to handle remote characters
*************************************************/
void doremote(c)
char c;
    {
    if (c == 27 || inesc >= 0) { doesc(c); return; }
    if (inctrl >= 0) { 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 */
    if (c < '0') {escseq[inesc++] = c; return; }  /* Collect intermediates */

    /* 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;
	a[0] = 0; a[1] = 0; sa[0] = 0; sa[1] = 0;
	emit(12); return;
	inesc = -1;
	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;

      /* 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 */
	    if (inctrl = 0) private = c; /* Only allowed BEFORE parameters */
	    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 any private sequences right now, so just punt
       them */

    if (private != 0 || badseq != 0) 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 '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  = 0;
		break;

		case 1:
		case 5:
		if (p_depth > 1)    curmode |= BOLD;
		else		    curmode |= REVERSE;
		break;

		case 4:
		curmode |= UNDERLINE;
		break;

		default:
		curmode |= 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 (p[0] == 20) nlmode = 1;
	return;

      case 'l':				/* Reset parameter */
	if (p[0] == 20) nlmode = 0;
	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;0c"); 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 'j':
	case 'm':
	case 'v':   doline(4,-8,4,-4);
	if      (c=='j')  doline(0,-4,4,-4);
	else if (c=='m')  doline(4,-4,8,-4);
	else              doline(0,-4,8,-4);
	break;

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

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

	case 't':
	case 'u':
	case 'x':   doline(4,-8,4,0);
	if      (c=='t')  doline(4,-4,8,-4);
	else if (c=='u')  doline(0,-4,4,-4);
	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
cat << \SHAR_EOF > script.c
/*************************************************************
 * vt100 terminal emulator - Script file support
 *
 *	     860823 DBW - Integrated and rewrote lots of code
 *	     860815 Steve Drew: Initial version written of SCRIPT.C
 *	v2.0 860809 DBW - Major rewrite
 *	v1.1 860720 DBW	- Switches, 80 cols, colors, bug fixes
 *	v1.0 860712 DBW	- First version released
 *
 *************************************************************/

#define MODULE_SCRIPT 1

#include "vt100.h"

extern	char *fgets(),*malloc();
extern	long ftell();

struct COMMAND {
                 int (*func)();
                 char *cname;
};

struct LABEL  {
                 struct LABEL *next;
                 char *name;
                 long pos;
};



/****************  globals  needed  ******************/

char		on_string[20];       /* string to match on for on cmd    */
char 		wait_string[20];     /* string to match of for wait cmd  */
char 		golabel[20];         /* label we are looking for in goto */
char 		on_cmd[255];         /* command to execute when on matchs*/
int 		onsize;		     /* size of on_string                */
int 		waitsize;            /* size of wait_string              */
int 		onpos;               /* position in on string for search */
int 		waitpos;             /* pos in wait_string for search    */
int 		on_match;            /* flag set while doing on_cmd      */
FILE 		*sf;                 /* file pointer for script file     */
struct LABEL 	*lbase = NULL;       /* will point to first label        */
struct LABEL 	*labels;             /* current label pointer            */

int  cmd_send(), cmd_wait(), cmd_on(), cmd_goto(), cmd_delay(), cmd_done(),
     cmd_ks(), cmd_kg(), cmd_kr(), cmd_xs(), cmd_xr(), cmd_cap(), cmd_as(),
     cmd_null(), cmd_kb();

char *next_wrd(), *tostring();


/********************** command table **********************************/

static struct COMMAND commands[]= {
                 cmd_send,   "SEND",         /* send string to host      */
                 cmd_wait,   "WAIT",         /* wait for a string from host */
                 cmd_on,     "ON", 	     /* on a 'string' do a cmd   */
                 cmd_goto,   "GOTO",         /* goto label               */
                 cmd_delay,  "DELAY",        /* delay amount of seconds  */
                 cmd_done,   "EXIT",         /* exit script file         */
                 cmd_ks,     "KS",           /* kermit send file         */
                 cmd_kr,     "KR",           /* kermit receive file      */
                 cmd_kg,     "KG",           /* kermit get file          */
		 cmd_kb,     "KB",	     /* kermit bye (for server)	 */
                 cmd_xs,     "XS",           /* xmodem send file         */
                 cmd_xr,     "XR",           /* xmodem receive file      */
                 cmd_cap,    "CAPTURE",      /* ascii capture on/off     */
                 cmd_as,     "ASCII_SEND",   /* ascii send               */
		 cmd_null,   NULL
};

/********************************************************************/
/* checks char to see if match with on string or wait_string        */
/* if on string match oncmd gets executed imediately,               */
/* if wait_string match script_wait is set.                         */
/********************************************************************/

chk_script(c)
char c;
{
    if (on_string[0] != '\0') {
        if (on_string[onpos] == c) {
            onpos++;
            if (onpos == onsize) {
                on_match = TRUE;
                do_script_cmd(ONCOMMAND); 
                on_match = FALSE;
                return(0);
            }
        }
        else onpos = 0;
    }

    if (wait_string[0] != '\0') {
       if (wait_string[waitpos] != c) {
            waitpos = 0;
            return(0);
        }
        waitpos++;
        if (waitpos != waitsize) return(0);
        wait_string[0] = '\0';
        script_wait = FALSE;
    }
}

script_start(file)
char *file;
{
    if ((sf = fopen(file, "r")) == NULL) {
        emits("Can't open script file\n");
        return(0);
    }
    script_on = TRUE;
    script_wait = FALSE;
    wait_string[0] = '\0';
    on_string[0] = '\0';
    on_match = FALSE;
    lbase = NULL;
}

/* return pointer to next word. set l to size of the word */

char *next_wrd(s,l)
char *s;
int *l;
{
    char *p;
    while(*s && (*s == ' ' || *s == 9)) s++;
    p = s;
    while(*s && (*s != ' ' && *s != 9)) s++;
    *l = s-p;
    return(p);
}

exe_cmd(p,l)
char *p;
int l;
{
    int i;
    
    for (i=0; commands[i].func != cmd_null; ++i) 
        if (strncmp(p, commands[i].cname, l) == 0) {
            (*commands[i].func)(next_wrd(p+l, &l));
            return(TRUE);
	}
        emits ("\nScript - unknown command: ");
        emits (p);
        emits ("\n"); 
}

struct LABEL *find_label(lname)
char *lname;
{
    struct LABEL *label;
  
    label = lbase;
    while(label != NULL) {
       if (strcmp(label->name, lname) == 0) return (label);
       label = label->next;
    }
    return(NULL);
}


do_script_cmd(stat)
int stat;
{
    int len,l;
    char line[256];
    char *p;

    if (stat == ONCOMMAND) {    /* if ON command is matched and we were     */
        strcpy(line,on_cmd);    /* doing a DELAY then abort the delay timer,*/
        p = next_wrd(line,&l);  /* except if on_cmd was just a SEND.        */
	if (*p != 'S' && script_wait == WAIT_TIMER)  {
            AbortIO((char *) &Script_Timer);
            Wait (1L << Script_Timer_Port->mp_SigBit);
            script_wait = FALSE; /* script will proceed after on command    */
        }
	exe_cmd(p,l);
        return(0);
    }

    script_wait = FALSE;
    while(fgets(line,256,sf) != NULL) {
       len = strlen(line);
       line[--len] = '\0';
       p = next_wrd(&line[0], &l);
       if (*(p + l - 1) == ':') {       	/* its a label */
           *(p + l - 1) = '\0';
           if (find_label(p) == NULL) {   	/* it's a new label */
               if (lbase == NULL)  {  		/* it's the first label */
                   labels = lbase = (struct LABEL *) malloc (sizeof (struct LABEL));
               }
               else {
                   labels->next = 
                           (struct LABEL *) malloc (sizeof (struct LABEL));
                   labels = labels->next;
               }
               labels->pos  = ftell(sf);
               labels->name = malloc(l);
               labels->next = NULL;
               strcpy(labels->name, p);
               if (stat == GOTOLABEL && strcmp(p, golabel) == 0) 
                      stat = NEXTCOMMAND;
           }
           if (l < len) p = next_wrd(p+l+1, &l);
           else return(0);
       } 	/* end of it's a label */
       if (stat == GOTOLABEL || *p == '#') continue;
       if (*p) exe_cmd(p,l);
       return(0);
    } 		/* end of while */
    if (stat == GOTOLABEL) {
          emits("\nScript - label not found: ");
          emits(golabel);
          emits("\n");
    }         
    exit_script();
}

exit_script()
{
    if (script_wait == WAIT_TIMER)      /* timer not done yet */
       AbortIO((char *) &Script_Timer); /* so abort it */
    emits("\nScript - terminated\n");    
    script_on = FALSE;
    script_wait = TRUE;
    fclose(sf);
}

/* remove quotes terminate string & return pointer to start */

char *tostring(ptr)
char *ptr;
{
    char *s;

    s = ptr;
    if (*ptr == '"') {
         while(*ptr++  && *ptr !='"');
         if (*ptr == '"') {
             *ptr = '\0';  
             ptr = s+1;
             while(*s++)  if (*s == '|') *s = '\r';
             return(ptr);
         }
    }
    if (*s == '^') {
        *s = *(s+1)-64;
        *(s+1) = '\0';
        return(s);
        }
    *(s+1) = '\0';
    return(s);
}   
        
cmd_goto(lname)
char *lname;
{
    struct LABEL *label;
   	                    /* if on_cmd was a goto kill wait state */
    if (on_match) { wait_string[0] = '\0'; script_wait = FALSE; }
    if ((label = find_label(lname)) == NULL) {  /* is it forward */
        strcpy(golabel,lname);
        do_script_cmd(GOTOLABEL);
    }
    else {
        fseek(sf,(long)(label->pos),0);
    }
}

cmd_send(str)
char *str;
{
  sendstring(tostring(str));
}

 
cmd_wait(str)
char *str;
{
        str = tostring(str);
        *(str+20) = '\0';         /* 20 characters max */
        strcpy(wait_string, str);
        waitsize = strlen(str);
        script_wait = WAIT_STRING;
}

cmd_on(str)
char *str;
{
   char *p;

   p = tostring(str);
   strcpy(on_string, p);
   onsize = strlen(p);
   *(p+onsize+2+20) = '\0';        /* 20 characters max */
   strcpy(on_cmd,p+onsize+2);
}

cmd_delay(seconds)
char *seconds;
{
    script_wait = WAIT_TIMER;
    Script_Timer.tr_time.tv_secs = atoi(seconds);
    Script_Timer.tr_time.tv_micro = 0;
    SendIO((char *) &Script_Timer.tr_node);
}

cmd_done()
{
    exit_script();
}

cmd_ks(file)
char *file;
{
   multi_xfer(file, doksend, 1);
}

cmd_kr(file)
char *file;
{
   multi_xfer(file, dokreceive, 0);
}

cmd_kg(file)
char *file;
{
   server = TRUE;
   multi_xfer(file, dokreceive, 0);
}

cmd_kb()
{
   saybye();
}

cmd_xs(file)
char *file;
{
   multi_xfer(file, XMODEM_Send_File, 1);
}

cmd_xr(file)
char *file;
{
   multi_xfer(file, XMODEM_Read_File, 1);
}

cmd_cap(file)
char *file;
{
do_capture(file);
}

cmd_as(file)
char *file;
{
do_send(file);
}

cmd_null(file)
char *file;
{
}

SHAR_EOF
#	End of shell archive
exit 0
Technical Details
Message-ID: <1965@j.cc.purdue.edu>
Path: arc1-ca.pugleaf.net!utzoo!mnetor!seismo!caip!princeton!allegra!ulysses!bellcore!whuxcc!lcuxlm!whuxl!houxm!ihnp4!inuxc!pur-ee!j.cc.purdue.edu!doc

Show Full Headers
Complete Article Headers
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: arc1-ca.pugleaf.net!utzoo!mnetor!seismo!caip!princeton!allegra!ulysses!bellcore!whuxcc!lcuxlm!whuxl!houxm!ihnp4!inuxc!pur-ee!j.cc.purdue.edu!doc
From: doc@pucc-j.UUCP
Newsgroups: mod.amiga.sources
Subject: New VT100 (part 2 of 2)
Message-ID: <1965@j.cc.purdue.edu>
Date: Wed, 3-Sep-86 02:53:46 EDT
Article-I.D.: j.1965
Posted: Wed Sep  3 02:53:46 1986
Date-Received: Thu, 4-Sep-86 20:16:44 EDT
Sender: doc@j.cc.purdue.edu
Organization: Purdue University Computing Center
Lines: 2095
Approved: doc@pucc-j.UUCP