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