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