Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!caip!princeton!allegra!ulysses!bellcore!whuxcc!lcuxlm!whuxl!houxm!ihnp4!inuxc!pur-ee!j.cc.purdue.edu!doc From: doc@pucc-j.UUCP Newsgroups: mod.amiga.sources Subject: New VT100 (part 1 of 2) Message-ID: <1964@j.cc.purdue.edu> Date: Wed, 3-Sep-86 02:53:37 EDT Article-I.D.: j.1964 Posted: Wed Sep 3 02:53:37 1986 Date-Received: Thu, 4-Sep-86 20:15:32 EDT Sender: doc@j.cc.purdue.edu Organization: Purdue University Computing Center Lines: 1882 Approved: doc@pucc-j.UUCP # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # readme # vt100.doc # makefile # vt100.c # vt100.h # window.c # xmodem.c # This archive created: Wed Sep 3 01:52:01 1986 # By: Craig Norborg (Purdue University Computing Center) cat << \SHAR_EOF > readme This archive contains a vt100 emulator with KERMIT and XMODEM file transfer protocols by Dave Wecker (V2.0 DBW 860823). Thanks: ------- A large part of this release is due to Dawn Banks and Steve Drew (lots of contributed code). Thanks for all of your efforts!! Releases: --------- v2.0 860823 DBW - Major rewrite v1.1 860720 DBW - Switches, 80 cols, colors, bug fixes v1.0 860712 DBW - First version released Usage: ------ Please read VT100.DOC for usage information and examples. Release Notes: -------------- v2.0 860823 DBW - Major rewrite: - Emulator now compiles under either MANX or LATTICE by defining the appropriate compiler type in VT100.H. - Sped up code to an effective baud rate of (about) 8k. This means that clear text at 4800 baud should be no problem. - Added XON/XOFF generation so that characters should not get lost any more at 9600 baud (when receiving clear text). - Got rid of all command line switches and environment variables. Instead upon invocation the program searches first for any file named on the command line, then looks for VT100.INIT in the current directory and finally searches for C:VT100.INIT. All parameters can be set in the init file, and a sample VT100.INIT is provided in VT100.DOC that shows all possible options. - All parameters that are set by VT100.INIT are defined in VT100.H (variables starting with "p_"). This allows you to compile your own defaults into the code. - You can now set the number of lines (for all you EMACS freaks :-). On an interlaced screen this gives you upto a 48 line terminal. - WORKBENCH colors are NEVER touched. - In an attempt to keep the size down, the color palette menu item has been removed (current). Code is about 36K in size with a run time image (using workbench screen) of about 88k. - Many bugs fixed including reverse scrolling with descenders, reverse video at end of line, clearing with scrolling regions, ... and 20 or more others. - File capture now no longer sends the filename to the host. - BOLD ([1m) has now been added by using an additional color when you specify a depth of 2 (instead of 1) bitplane. - UNDERLINE ([4m) has now been added. - The handling of remote (host) escape sequences has been completly re-written (thanks to Dawn Banks for all the work). - Function keys (and shifted function keys) can now be bound to arbitrary strings (Jim Ravan gets his macros). See VT100.DOC for details. - Cursor has no been reduced to the size of a normal character for easier readability. - XMODEM has been improved (by Steve Drew) to use a timer device (for timeouts) and to abort immediately if the user types . - KERMIT has been completely re-written and appears to work fine, thanks to the efforts of Steve Drew. Items include: - supports multi-file transfer in both send and receive modes - works with binary files (tried with VAX/vms and VAX/unix) - now has Get file for use with server (receiving files) - Kermit BYE item will send server bye command. - A final filename of dollar sign ("$") will send a BYE to the host KERMIT server. - status bar shows pkt type, pkt no., total retransmissions, filename, total bytes xfered and status which can be: SEND - sending this file RECV - receiving this file ABORT - user hit escape to abort transfer.. TMOUT - did not receive characters before timeout ERROR - some other error detected. DONE - transfer complete - now uses timer.device to determine if timeout occurrs. - will cleanly abort when user hits if in send mode tells host to discard the partial file. - New menu item allows script file support. Module written by Steve Drew. See VT100.DOC for details. Known problems: --------------- - none yet (need to hear what still doesn't work right). Yet to be done (possibly.. not promising anything): --------------------------------------------------- - Add sending/receiving of entire volumes (with data compression). Maybe use LZW compression. - Add BOO file transfer mode for encoding/decoding binary files into clear text. Installation: ------------- The files in this archive may be extracted by the bourne shell (/bin/sh) or the shar program using the "unshar switch (-u)", contact me if you need a copy of this version of shar. Files: ------ README - this file vt100.doc - documentation for the terminal emulator makefile - make file for the emulator (under MANX AZTEC-C) vt100.h - include file used by all other modules window.c - manager for window and keyboard vt100.c - main module, handles menus remote.c - handle remote characters (vt100 emulation) kermit.c - kermit protocol (to transfer text files on VMS select the CRLF option on the transfer mode menu, otherwise use image mode). init.c - startup code xmodem.c - xmodem protocol that understands AMIGA binary and text file formats (automatically). script.c - script control package Contact: -------- Please send bugs/comments/suggestions to: Dave Wecker at ENET: COOKIE::WECKER ARPA: wecker%cookie.dec.com@decwrl.dec.com USENET: {decvax|decwrl}!cookie.dec.com!wecker SNAIL: Dave Wecker 115 Palm Springs Drive Colorado Springs, CO 80908 SHAR_EOF cat << \SHAR_EOF > vt100.doc This is the documentation file for the VT100 terminal emulator by Dave Wecker (V2.0 DBW 860823). Comments/suggestions/bugs/problems/praise should be sent to: Dave Wecker at ENET: COOKIE::WECKER ARPA: wecker%cookie.dec.com@decwrl.dec.com USENET: {decvax|decwrl}!cookie.dec.com!wecker SNAIL: Dave Wecker 115 Palm Springs Drive Colorado Springs, CO 80908 Multi-file transfer, the new version of KERMIT and script support were contributed by Steve Drew (Aug 20 1986). If you wish to thank Steve directly he can be contacted through: Steve Drew at ENET: CGFSV1::DREW ARPA: drew%cfgsv1.dec.com@decwrl.dec.com USENET: decvax!decwrl!cgfsv1.dec.com!drew Program startup: ---------------- 1> vt100 [initfile] - At startup, the program will search for an initialization file to execute. It will first look for "initfile", then VT100.INIT (in the current directory) and finally C:VT100.INIT. The format for the init file is described later in this document. - The init file controls the setting of initial defaults and screen and macro definitions. - If none of the files (listed above) are found, the built-in defaults (defined in VT100.H as variables, beginning with "p_") are used. - All commands are either menu or script based. Scripts are described below. Keypad mapping: --------------- AMIGA VT100 comments ------- ------- --------------------------- 0-9 == 0-9 . == . ENTER == ENTER (basically, flip the bottom - == , 2 keys up to get a VT100) HELP == - (only free key around) f1-f4 == PF1-PF4 (or any rebinding you do) arrows == arrows Initialization file example: ---------------------------- Here is a (hopefully) self-explanatory VT100.INIT file with all options used: ####################################################################### # # VT100 sample initialization file # v2.0 860823 DBW - Dave Wecker standard defaults # # Hash mark at the beginning of a line denotes a comment. # White space (space(s) or tab(s)) delimit fields. # Case ignored except for function key bindings. # # All items in this file overide variables of the same name in VT100.H # (all variables in vt100.h have a "p_" prepended to them) # ########################################################################## # BAUD 2400 # Anything after required fields is ignored SCREEN WORKBENCH # may be CUSTOM or WORKBENCH INTERLACE OFF # ON for CUSTOM or interlaced workbench DEPTH 2 # number of bit planes to use (1 or 2) FOREGROUND 840 # Colors are only used on the custom screen BACKGROUND 000 # Colors are in hex RGB from 000 to FFF BOLD c00 # Color for bold highlighting (in custom) CURSOR 888 # Color for cursor (in custom screen) LINES 24 # normal <= 24 interlaced <= 48 MODE IMAGE # IMAGE or CRLF (for KERMIT transfers) XOFF ENABLED # Do you want automatic XON/XOFF flow cntrl # # Function bindings (strings to type when any of F1 through F10 are pressed) # f = function key # F = shifted function key # # The string specified must be delimited and uses one special character: # ^ = control next character # ^^ = up arrow # # Sample control characters: # ^[ = escape ^M = carriage return # ^J = line feed ^L = form feed # # Examples of bindings: # f1 "^[OP" # f1-f4 = PF1 - PF4 on a VT100 f2 "^[OQ" f3 "^[OR" f4 "^[OS" f6 "MAIL^M" # Reads my mail (note embedded ) f7 "NOTE^M" # Reads conferences F1 "$2400!" # dials the phone to work F2 "$bbs1!" # dials the phone to billboard 1 F3 "$bbs2!" # dials the phone to billboard 2 F4 "$bbs3!" # dials the phone to billboard 3 # exit # all done (clean way to end file) Multi file Xfers: ----------------- The VT100 emulator now supports multiple file transfers. This is specified by using a comma (",") between file names when using XMODEM or KERMIT. (Note: host XMODEM's normally CANNOT support multiple file transfers). When specifying a file name to recieve by default the directory path is stripped of the filename when sent to the host but is kept for the local file spec. eg: receive file: ram:file.txt,df1:newfile.bin,$ will ask the server for file.txt and put it in ram:, and get newfile.bin and put it on df1: (see explanation of "$" below). If you do a single file transfer you will get another prompt for the remote name e.g.: receive file: ram:file.txt remote file name[file.txt] userdisk1:wantfile.txt The same rules apply to sending multiple files therefore if you are doing multi file transfers make sure the host server is connected to the desired directory. Script file operation: ---------------------- The script file can be invoked by selecting 'execute file' from the script menu. At any time you can abort the script file by selecting 'Abort Execution'. During the time script file is running the terminal emulation is still active and you may type simulataneous to the script file. This may be desired if your script file is WAITing for a string or is DELAYing for a period of time etc. Script file Commands: --------------------- # Commented line Format: # comment may not be on same line as a command. Example: # this is a comment ------------------------------------------------------------ ASCII_SEND Send an ascii file to the host. Format: (same format as CAPTURE) ------------------------------------------------------------ CAPTURE To start/stop ascii file capture. Format: CAPTURE file Start ascii capturing CAPTURE End ascii capturing Example: CAPTURE foo.bar Starts capture of file foo.bar CAPTURE Ends ascii capture of file foo.bar ------------------------------------------------------------ DELAY Suspends script file for a specified time Format: DELAY n Suspends execution for n seconds Example: DELAY 2 Suspends for 2 seconds ------------------------------------------------------------ EXIT Ends execution of the script file. Format: EXIT ------------------------------------------------------------ GOTO Jumps to a different part of the script file. Format: GOTO label Jumps to a line beginning with label: Jumps may be forward or backward. Example: FOO: Sets up a label GOTO FOO Jumps to FOO ------------------------------------------------------------ KB Send a BYE packet to a host KERMIT server (shut down server). Format: KB ------------------------------------------------------------ KG Gets files from host. (which is running as a server). Format: (same format as KS) ------------------------------------------------------------ KR Receives a file from kermit host (not running as server) Format: (same format as KS) ------------------------------------------------------------ KS Sends files via kermit to the host. Format: KS file Send one file KS file1,file2,... Send multiple files KS file1,file2,...,$ Send multiple files and shut down server Example: KS foo.bar sends foo.bar (note no quoting is used) KS foo1,foo2,foo3 sends three files KS foo1,foo2,foo3,$ sends three files and shuts down server ------------------------------------------------------------ ON Peforms a command every time a string is received Format: ON "string" cmd Execute cmd when string is received. Only one ON string may be installed at a time. If cmd is a GOTO and we were previously WAITing for a string the WAIT is aborted and execution resumes at the new label. If cmd is not SEND and we were previously DELAYing, then the DELAY is aborted and the cmd is executed, followed by the next command after the DELAY. If cmd is a SEND and we were previously DELAYing, then the DELAY is continued. Example: ON "LOSS CARRIER" GOTO RESTART If modem drops carrier, try to redial ON "--more--" SEND " " Send a space every time --more-- is received ------------------------------------------------------------ SEND Sends a string or character to the host. Format: SEND "string" Sends a string to the host. Beginning and ending double quotes (") are required. A vertical bar may be used to send a . SEND chr Sends a single character. SEND ^chr Sends a single control character. The chr must be an upper case letter. Example: SEND "mail" Send the string mail SEND "dir|" Send the string dir followed by a SEND a Send the letter a SEND ^C Send a control C ------------------------------------------------------------ WAIT Suspends the script file until a certain string is received. Format: WAIT "string" Same rules for string as SEND WAIT Enter an endless wait. Usually used after some "ON" commands have been set up. Can still aborted via the script menu. Example: WAIT "User:" Waits for the string User: WAIT Waits forever ------------------------------------------------------------ XR Receives a file via XMODEM. Format: (same format as KS) ------------------------------------------------------------ XS Sends a file via XMODEM. Format: (same format as KS) ------------------------------------------------------------ Script file example: -------------------- # # Script to upload the terminal emulator sources to my host system # v1.0 860823 DBW # # First get the modem's attention: # Start: DELAY 1 ON "Ready" GOTO Dial SEND ^B DELAY 2 GOTO Start # # Now dial the 2400 baud line to work: # Dial: ON "Attached" GOTO Login SEND "$2400!" DELAY 30 GOTO Start # # We got attached, so keep hitting return until the Gandalf terminal # handler wakes up: # Login: ON "enter" GOTO Gandalf DELAY 1 SEND "|" GOTO Login # # Now connect from the Gandalf to the terminal server (ts1): # (when it asks for a password I need to type the password manually here) # Gandalf: DELAY 1 SEND "ts1|" WAIT "class start" # # Keep sending 's until the LAT prompts for a username: # WaitLat: DELAY 1 ON "username>" GOTO Lat SEND "|" GOTO WaitLat # # Tell the LAT that it's me, and connect to the "cookie cluster" (my host # systems). Tell the cluster my user name. # (when it asks for a password I need to type the password manually here) # Lat: SEND "wecker|" DELAY 1 SEND "connect cookie|" WAIT "Username:" SEND "WECKER|" WAIT "at home" SEND "||" # # Got through all the LOGIN garbage, so let's do some work. # WAIT "$ " # # Get into the right directory and no broadcast mode # SEND "set term/nobroad|" SEND "set default [wecker.amiga.vt100]|" WAIT "$ " # # Send the shar file for the terminal emulator via XMODEM: # SEND "xmodem -r vt100.shar|" DELAY 3 XS vt100.shar WAIT "$ " # # Send the shar file via KERMIT (assumes that the emulator is in CRLF mode): # KermitShar: DELAY 1 SEND "kermit|server|" DELAY 3 KS vt100.shar DELAY 1 KB SEND "|exit|" WAIT "$ " # # Start up kermit and upload each source file separately # (on VMS this assumes that our transfer mode is CRLF (not image)) # SEND "kermit|server|" DELAY 3 KS readme,vt100.doc,makefile,vt100.h,vt100.c,init.c,window.c KS xmodem.c,remote.c,kermit.c,script.c,$ # # We popped out of server mode, so exit and we're done # SEND "|exit|" EXIT SHAR_EOF cat << \SHAR_EOF > makefile ###################################################################### # # Makefile to build vt100 terminal emulator # # 860823 DBW - Integrated and rewrote lots of code # v2.0 860809 DBW - Major release.. LOTS of changes # v1.1 860720 DBW - Switches, 80 cols, colors, bug fixes # v1.0 860712 DBW - First version released # ###################################################################### OBJS = vt100.o init.o window.o xmodem.o remote.o kermit.o script.o INCL = vt100.h #INCL = #REDIR = > PRT: REDIR = vt100 : $(OBJS) ln $(REDIR) -v -o vt100 $(OBJS) -lc vt100.o : vt100.c $(INCL) cc $(REDIR) -b +Hvt100.syms vt100.c init.o : init.c $(INCL) cc $(REDIR) -b +Ivt100.syms init.c window.o : window.c $(INCL) cc $(REDIR) -b +Ivt100.syms window.c xmodem.o : xmodem.c $(INCL) cc $(REDIR) -b +Ivt100.syms xmodem.c remote.o : remote.c $(INCL) cc $(REDIR) -b +Ivt100.syms remote.c kermit.o : kermit.c $(INCL) cc $(REDIR) -b +Ivt100.syms kermit.c script.o : script.c $(INCL) cc $(REDIR) -b +Ivt100.syms script.c SHAR_EOF cat << \SHAR_EOF > vt100.c /************************************************************************ * vt100 terminal emulator with xmodem transfer capability * * 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 * * use to abort xmodem or kermit transfers * * written by Michael Mounier * new version by Dave Wecker ************************************************************************/ /* all includes defines and globals */ #define MODULE_MAIN 1 #include "vt100.h" /******************************************************/ /* Main Program */ /* */ /* This is the main body of the program. */ /******************************************************/ char lookahead[2048]; FILE *tranr = NULL; FILE *trans = NULL; int capture,send; char name[256]; main(argc,argv) int argc; char **argv; { ULONG class; unsigned int code,menunum,itemnum; int KeepGoing,i,j,la,dola,xonflg,rxonflg,actual; char c; InitDefaults(argc,argv); InitDevs(); InitFileItems(); InitRSItems(); InitXFItems(); InitScriptItems(); InitMenu(); SetMenuStrip(mywindow,&menu[0]); KeepGoing = TRUE; capture = FALSE; send = FALSE; xonflg = FALSE; rxonflg = FALSE; maxcol = MAXX / 8; la = 0; x = MINX ; y = MINY; curmode = 0; script_on = FALSE; script_wait= TRUE; SetAPen(mywindow->RPort,1L); cursoron(); cursoroff(); emit(12); BeginIO(Read_Request); while( KeepGoing ) { /* wait for window message or serial port message */ cursoron(); if (script_wait) /* if script ready dont wait here */ Wait( (1L << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit) | (1L << mywindow->UserPort->mp_SigBit) | (1L << Script_Timer_Port->mp_SigBit)); cursoroff(); /* do ascii file send */ if (send) { if ((c=getc(trans)) != EOF) { if (c == '\n') c = '\r'; sendchar(c); } else { fclose(trans); emits("\nFile Sent\n"); send=FALSE; } } /* see if there are any characters from the host */ if (CheckIO(Read_Request)) { WaitIO(Read_Request); c = rs_in[0] & 0x7F; doremote(c); if (script_on) chk_script(c); if (capture && c != 10) { if (c == 13) c = 10; putc(c , tranr); } Read_Request->IOSer.io_Command = SDCMD_QUERY; BeginIO(Read_Request); WaitIO(Read_Request); Read_Request->IOSer.io_Command = CMD_READ; actual = (int)Read_Request->IOSer.io_Actual; if (actual > 0) { if (inesc < 0 && inctrl < 0 && a[alt] == 0 && capture == FALSE) dola = 1; else dola = 0; Read_Request->IOSer.io_Length = Read_Request->IOSer.io_Actual; BeginIO(Read_Request); WaitIO(Read_Request); Read_Request->IOSer.io_Length = 1; /* if too many use XON/XOFF */ if (p_xon && actual > 1536 && xonflg == FALSE) { sendchar(19); xonflg = TRUE; } for (i = 0; i < actual; i++) { c=rs_in[i] & 0x7f; if (script_on) chk_script(c); /* handle host request for flow control */ if (p_xon) { if (rxonflg) { if (c == 17) { rxonflg = FALSE; } continue; } else if (c == 19) { rxonflg = TRUE; continue; } } if (dola == 1) { if (c >= ' ' && c <= '~') lookahead[la++] = c; else { if (la > 0) { emitbatch(la,lookahead); la = 0; } doremote(c); dola = 0; } } else { doremote(c); if (p_xon && xonflg == FALSE && i == 1023) { Read_Request->IOSer.io_Command = SDCMD_QUERY; BeginIO(Read_Request); WaitIO(Read_Request); Read_Request->IOSer.io_Command = CMD_READ; j = (int)Read_Request->IOSer.io_Actual; if (j > 1023) { sendchar(19); xonflg = TRUE; } } if (inesc < 0 && inctrl < 0 && a[alt] == 0 && capture == FALSE) dola = 1; if (capture && c != 10) { if (c == 13) c = 10; putc(c , tranr); } } } /* dump anything left in the lookahead buffer */ if (la > 0) { emitbatch(la,lookahead); la = 0; } /* tell host to resume transmission */ if (xonflg == TRUE) { sendchar(17); xonflg = FALSE; } } BeginIO(Read_Request); /* wait for host to tell us to resume */ while (rxonflg == TRUE) { WaitIO(Read_Request); if ((rs_in[0] & 0x7F) == 17) rxonflg = FALSE; BeginIO(Read_Request); } } while( NewMessage=(struct IntuiMessage *)GetMsg(mywindow->UserPort) ) { class = NewMessage->Class; code = NewMessage->Code; ReplyMsg( NewMessage ); switch( class ) { case CLOSEWINDOW: KeepGoing = FALSE; break; case RAWKEY: c = toasc(code,0); break; case NEWSIZE: emit(12); break; case MENUPICK: if ( code != MENUNULL ) { menunum = MENUNUM( code ); itemnum = ITEMNUM( code ); switch( menunum ) { case 0: switch( itemnum ) { case 0: do_capture(NULL); break; case 1: do_send(NULL); break; case 2: emits("\nXmodem Receive:"); filename(name); multi_xfer(name,XMODEM_Read_File,0); break; case 3: emits("\nXmodem Send:"); filename(name); multi_xfer(name,XMODEM_Send_File,1); break; case 4: server = TRUE; itemnum = 5; case 5: emits("\nKermit Receive local name:"); filename(name); multi_xfer(name,dokreceive,0); break; case 6: server = TRUE; emits("\nKermit Send local name:"); filename(name); multi_xfer(name,doksend,1); break; case 7: saybye(); break; } break; case 1: AbortIO(Read_Request); switch( itemnum ) { case 0: Read_Request->io_Baud = 300; break; case 1: Read_Request->io_Baud = 1200; break; case 2: Read_Request->io_Baud = 2400; break; case 3: Read_Request->io_Baud = 4800; break; case 4: Read_Request->io_Baud = 9600; break; } Read_Request->IOSer.io_Command = SDCMD_SETPARAMS; DoIO(Read_Request); Read_Request->IOSer.io_Command = CMD_READ; BeginIO(Read_Request); break; case 2: p_mode = itemnum; break; case 3: if (!itemnum && !script_on) { emits("Script file name: "); filename(name); script_start(name); } if (itemnum && script_on) { exit_script(); } break; } /* end of switch ( menunum ) */ } /* end of if ( not null ) */ } /* end of switch (class) */ } /* end of while ( newmessage )*/ if (!script_wait || (CheckIO(&Script_Timer) && script_wait == WAIT_TIMER)) do_script_cmd(NEXTCOMMAND); } /* end while ( keepgoing ) */ /* It must be time to quit, so we have to clean * up and exit. */ CloseDevice(&Timer); DeletePort(Timer_Port); CloseDevice(&Script_Timer); DeletePort(Script_Timer_Port); CloseDevice(Read_Request); DeletePort(Read_Request->IOSer.io_Message.mn_ReplyPort); FreeMem(Read_Request,(long)sizeof(*Read_Request)); CloseDevice(Write_Request); DeletePort(Write_Request->IOSer.io_Message.mn_ReplyPort); FreeMem(Write_Request,(long)sizeof(*Write_Request)); ClearMenuStrip( mywindow ); CloseWindow( mywindow ); if (p_screen != 0) CloseScreen( myscreen ); exit(FALSE); } /* end of main */ do_capture(file) char *file; { if (capture == TRUE) { capture=FALSE; fclose(tranr); emits("\nEnd File Capture\n"); } else { if (file == NULL) { emits("\nAscii Capture:"); filename(name); } else strcpy(name, file); if ((tranr=fopen(name,"w")) == 0) { capture=FALSE; emits("\nError Opening File\n"); return(FALSE); } capture=TRUE; } } do_send(file) char *file; { if (send == TRUE) { send=FALSE; fclose(trans); emits("\nFile Send Cancelled\n"); } else { if (file == NULL) { emits("\nAscii Send:"); filename(name); } else strcpy(name, file); if ((trans=fopen(name,"r")) == 0) { send=FALSE; emits("\nError Opening File\n"); return(FALSE); } send=TRUE; } } SHAR_EOF cat << \SHAR_EOF > vt100.h /********************************************************************* * a terminal program that has ascii and xmodem transfer capability * * 860823 DBW - Integrated and rewrote lots of code * v2.0 860809 DBW - Major release.. LOTS of changes * v1.1 860720 DBW - Switches, 80 cols, colors, bug fixes * v1.0 860712 DBW - First version released * * use esc to abort xmodem transfer * * written by Michael Mounier * new version by Dave Wecker 860621 ************************************************************************/ /* define the compiler type here */ #define LATTICE 0 #define MANX 1 /* compiler directives to fetch the necessary header files */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if MANX #include #undef NULL #define NULL ((void *)0) #endif #define INTUITION_REV 1L #define GRAPHICS_REV 1L /* things for xmodem send and recieve */ #define GOODREAD 0 #define TIMEOUT 1 #define USERABORT 2 #define SECSIZ 0x80 #define TTIME_SHORT 5 /* number of seconds for short timeout */ #define TTIME_LONG 50 /* number of seconds for long timeout */ #define BufSize 0x1000 /* Text buffer */ #define ERRORMAX 10 /* Max errors before abort */ #define RETRYMAX 10 /* Maximum retrys before abort */ #define SOH 1 /* Start of sector char */ #define EOT 4 /* end of transmission char */ #define ACK 6 /* acknowledge sector transmission */ #define NAK 21 /* error in transmission detected */ #define FILEMAX 8 /* number of file menu items */ #define RSMAX 5 /* speed menu items */ #define XFMAX 2 /* transfer mode items */ #define SCRIPTMAX 2 /* script menu items */ #define MAXMENU 4 /* total number of menu entries */ #define BOLD 1 /* modes in curmode and savmode */ #define UNDERLINE 2 #define REVERSE 4 #define BLINK 8 /* things for script support */ #define GOTOLABEL 1 #define NEXTCOMMAND 0 #define ONCOMMAND 2 #define WAIT_TIMER 2 #define WAIT_STRING 1 extern struct MsgPort *CreatePort(); #ifdef MODULE_MAIN char bufr[BufSize]; int fd, timeout = FALSE, ttime; int multi = FALSE, server; long bytes_xferred; struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct NewScreen NewScreen = { 0L,197L,640L,205L,1L, /* left, top, width, height, depth */ 0,1,HIRES, /* DetailPen, BlockPen, ViewModes */ CUSTOMSCREEN,NULL, /* Type, Font */ (UBYTE *)"VT100 Terminal Screen", /* Title */ NULL,NULL }; /* Gadgets, Bitmap */ struct NewWindow NewWindow = { 0,3L,640L,200L, /* left, top, width, height */ 0,1, /* detailpen, blockpen */ MENUPICK | CLOSEWINDOW | RAWKEY | NEWSIZE, SMART_REFRESH | REPORTMOUSE | ACTIVATE | BORDERLESS | WINDOWCLOSE | WINDOWDEPTH | WINDOWDRAG, /* Flags */ NULL,NULL, /* FirstGadget, CheckMark */ (UBYTE *) "VT100 Terminal Window ", NULL, /* set screen after open screen */ NULL, /* bitmap */ 640L, 200L, 640L, 200L,/* minw, minh, maxw, maxh */ CUSTOMSCREEN /* Type */ }; struct Screen *myscreen; /* ptr to applications screen */ struct Window *mywindow; /* ptr to applications window */ struct ViewPort *myviewport; struct IntuiMessage *NewMessage; /* msg structure for GetMsg() */ struct Preferences *Prefs; /* preferences from GetPrefs() */ struct MenuItem FileItem[FILEMAX]; struct IntuiText FileText[FILEMAX]; struct MenuItem RSItem[RSMAX]; struct IntuiText RSText[RSMAX]; struct MenuItem XFItem[XFMAX]; struct IntuiText XFText[XFMAX]; struct MenuItem ScriptItem[SCRIPTMAX]; struct IntuiText ScriptText[SCRIPTMAX]; struct Menu menu[MAXMENU]; struct IOExtSer *Read_Request; char rs_in[2048]; struct IOExtSer *Write_Request; char rs_out[2]; struct timerequest Timer; struct MsgPort *Timer_Port = NULL; struct timerequest Script_Timer; struct MsgPort *Script_Timer_Port = NULL; int want_message; int x,y,curmode; int MINX = 0; int MAXX = 632; int MINY = 14; int MAXY = 198; int top = 14; int bot = 198; int savx = 0; int savy = 14; int savmode = 0; int nlmode = 0; int alt = 0; int savalt = 0; int a[2] = { 0, 0 }; int sa[2] = { 0, 0 }; int inesc = -1; int inctrl = -1; int private = 0; int badseq = 0; char *blanks = " "; int maxcol = 79; /*************************** defaults ***********************************/ int p_baud = 2400; /* baud rate */ int p_screen = 0; /* 0 = WORKBENCH, 1 = CUSTOM */ int p_interlace = 0; /* 0 = no interlace, 1 = interlace */ int p_depth = 2; /* number of bit planes (1 or 2) */ int p_foreground = 0x840; /* default foreground RGB color */ int p_background = 0x000; /* default background RGB color */ int p_bold = 0xa00; /* default BOLD RGB color */ int p_cursor = 0x00d; /* default Cursor RGB color */ int p_lines = 24; /* number of lines on the screen */ int p_mode = 0; /* 0 = image, 1 = CRLF (for kermit) */ int p_xon = 0; /* 0 = disabled, 1 = enabled */ char *p_f[10] = { /* function key defaults */ "\033OP","\033OQ","\033OR","\033OS", "f5","f6","f7","f8","f9","f10" }; char *p_F[10] = { /* shifted function key defaults */ "F1","F2","F3","F4","F5", "F6","F7","F8","F9","F10"}; /* for script file */ int script_on; int script_wait; #else /* not MODULE_MAIN */ extern int multi; /* flags multi file transfers */ extern int server; extern int want_message; extern char bufr[BufSize]; extern int fd, timeout, ttime; extern long bytes_xferred; extern struct IntuitionBase *IntuitionBase; extern struct GfxBase *GfxBase; extern struct NewScreen NewScreen; extern struct NewWindow NewWindow; extern struct Screen *myscreen; extern struct Window *mywindow; extern struct ViewPort *myviewport; extern struct IntuiMessage *NewMessage; extern struct Preferences *Prefs; extern struct MenuItem FileItem[FILEMAX]; extern struct IntuiText FileText[FILEMAX]; extern struct MenuItem RSItem[RSMAX]; extern struct IntuiText RSText[RSMAX]; extern struct MenuItem XFItem[XFMAX]; extern struct IntuiText XFText[XFMAX]; extern struct MenuItem ScriptItem[SCRIPTMAX]; extern struct IntuiText ScriptText[SCRIPTMAX]; extern struct Menu menu[MAXMENU]; extern struct timerequest Timer, Script_Timer; extern struct MsgPort *Timer_Port, *Script_Timer_Port; extern struct IOExtSer *Read_Request; extern char rs_in[2048]; extern struct IOExtSer *Write_Request; extern char rs_out[2]; extern int x,y,curmode; extern int MINX,MAXX,MINY,MAXY,top,bot,savx,savy; extern int savmode,nlmode,alt,savalt,a[2],sa[2]; extern int inesc,inctrl,private,badseq,maxcol; extern char *blanks; extern int p_baud,p_screen,p_interlace,p_depth; extern int p_foreground,p_background,p_bold,p_cursor,p_lines,p_mode,p_xon; extern char *p_f[10],*p_F[10]; extern int script_on; extern int script_wait; extern int do_send(),do_capture(); #endif /* not MODULE_MAIN */ #ifndef MODULE_INIT extern void InitDefaults(),InitDevs(),InitFileItems(),InitRSItems(), InitXFItems(),InitScriptItems(),InitMenu(); #endif #ifndef MODULE_WINDOW extern void filename(),emits(),emit(),emitbatch(),cursoroff(),cursoron(); extern int toasc(); #endif #ifndef MODULE_XMODEM extern void sendchar(),sendstring(); extern int readchar(),XMODEM_Read_File(),XMODEM_Send_File(); #endif #ifndef MODULE_REMOTE extern void doremote(),doindex(); #endif #ifndef MODULE_KERMIT extern int doksend(),dokreceive(), multi_xfer(), saybye(); #endif #ifndef MODULE_SCRIPT extern int script_start(), chk_script(), exit_script(), do_script_cmd(); #endif SHAR_EOF cat << \SHAR_EOF > window.c /**************************************************** * vt100 emulator - window/keyboard support * * 860823 DBW - Integrated and rewrote lots of code * v2.0 860809 DBW - Major rewrite * v1.1 860720 DBW - Switches, 80 cols, colors, bug fixes * v1.0 860712 DBW - First version released * ****************************************************/ #define MODULE_WINDOW 1 #include "vt100.h" /* forward declarations for LATTICE */ void filename(); void emits(); void emit(); void emitbatch(); void cursoroff(); void cursoron(); /************************************************* * function to get file name *************************************************/ void filename(name) char name[]; { char c; ULONG class; unsigned int code; int keepgoing,i; keepgoing = TRUE; i=0; while (keepgoing) { while( NewMessage=(struct IntuiMessage *)GetMsg(mywindow->UserPort) ) { class = NewMessage->Class; code = NewMessage->Code; ReplyMsg( NewMessage ); if (class=RAWKEY) { c = toasc(code,1); name[i]=c; if (name[i] != 0) { if (name[i] == 13) { name[i]=0; keepgoing = FALSE; } else { if (name[i] == 8 || name[i] == 127) { i -= 2; if (i < -1) i = -1; else { if (x == MINX) { y -= 8; x = MAXX; } emit(8); emit(32); emit(8); } } else emit(c); if (x == MAXX) emits("\n"); } i += 1; } } } /* end of new message loop */ } /* end of god knows what */ emit(13); emit(10); } /* end of function */ /************************************************* * function to print a string *************************************************/ void emits(string) char string[]; { int i; char c; i=0; while (string[i] != 0) { c=string[i]; if (c == 10) emit(13); emit(c); i += 1; } } /************************************************* * function to output ascii chars to window *************************************************/ void emit(c) char c; { Move(mywindow->RPort,(long)x,(long)y); c &= 0x7F; switch( c ) { case '\t': x += 64 - ((x-MINX) % 64); break; case 10: /* lf */ y += 8; break; case 13: /* cr */ x = MINX; break; case 8: /* backspace */ x -= 8; if (x < MINX) x = MINX; break; case 12: /* page */ x = MINX; y = MINY; SetAPen(mywindow->RPort,0L); RectFill(mywindow->RPort,(long)MINX, (long)(MINY-7),(long)(MAXX+7),(long)(MAXY+1)); SetAPen(mywindow->RPort,1L); break; case 7: /* bell */ DisplayBeep(NULL); ClipBlit(mywindow->RPort,0L,0L,mywindow->RPort,0L,0L, (long)MAXX,(long)MAXY,0x50L); ClipBlit(mywindow->RPort,0L,0L,mywindow->RPort,0L,0L, (long)MAXX,(long)MAXY,0x50L); break; default: if (c < ' ' || c > '~') break; if (curmode&REVERSE) { Text(mywindow->RPort," ",1L); Move(mywindow->RPort,(long)x,(long)y); SetDrMd(mywindow->RPort,(long)INVERSVID); if (curmode&BOLD) SetAPen(mywindow->RPort,(long)(2+(1^p_screen))); Text(mywindow->RPort,&c,1L); if (curmode&UNDERLINE) RectFill(mywindow->RPort, (long)(x-1),(long)(y+1),(long)(x+8),(long)(y+1)); if (curmode&BOLD) SetAPen(mywindow->RPort,1L); SetDrMd(mywindow->RPort,(long)JAM2); } else { if (curmode&BOLD) SetAPen(mywindow->RPort,(long)(2+(1^p_screen))); Text(mywindow->RPort,&c,1L); if (curmode&UNDERLINE) RectFill(mywindow->RPort, (long)(x-1),(long)(y+1),(long)(x+8),(long)(y+1)); if (curmode&BOLD) SetAPen(mywindow->RPort,1L); } x += 8; } /* end of switch */ while (x > MAXX) x -= 8; while (y > MAXY) { y -= 8; x = MINX; ScrollRaster(mywindow->RPort,0L,8L,(long)MINX, (long)(MINY-6),(long)(MAXX+7),(long)(MAXY+1)); } } /************************************************* * function to output ascii chars to window (batched) *************************************************/ void emitbatch(la,lookahead) int la; char *lookahead; { int i; Move(mywindow->RPort,(long)x,(long)y); i = x / 8; if (i+la > maxcol) la = maxcol-i; if (curmode&REVERSE) { Text(mywindow->RPort,blanks,(long)la); Move(mywindow->RPort,(long)x,(long)y); SetDrMd(mywindow->RPort,(long)INVERSVID); if (curmode&BOLD) SetAPen(mywindow->RPort,(long)(2+(1^p_screen))); Text(mywindow->RPort,lookahead,(long)la); if (curmode&UNDERLINE) RectFill(mywindow->RPort, (long)(x-1),(long)(y+1),(long)((x+8*la)+8),(long)(y+1)); if (curmode&BOLD) SetAPen(mywindow->RPort,1L); SetDrMd(mywindow->RPort,(long)JAM2); } else { if (curmode&BOLD) SetAPen(mywindow->RPort,(long)(2+(1^p_screen))); Text(mywindow->RPort,lookahead,(long)la); if (curmode&UNDERLINE) RectFill(mywindow->RPort, (long)(x-1),(long)(y+1),(long)((x+8*la)+8),(long)(y+1)); if (curmode&BOLD) SetAPen(mywindow->RPort,1L); } x += (8 * la); } /****************************** * Manipulate cursor ******************************/ void cursoroff() { SetDrMd(mywindow->RPort,(long)COMPLEMENT); SetAPen(mywindow->RPort,3L); RectFill(mywindow->RPort, (long)(x-1),(long)(y-6),(long)(x+8),(long)(y+1)); SetAPen(mywindow->RPort,1L); SetDrMd(mywindow->RPort,(long)JAM2); } void cursoron() { SetDrMd(mywindow->RPort,(long)COMPLEMENT); SetAPen(mywindow->RPort,3L); RectFill(mywindow->RPort, (long)(x-1),(long)(y-6),(long)(x+8),(long)(y+1)); SetAPen(mywindow->RPort,1L); SetDrMd(mywindow->RPort,(long)JAM2); } /************************************************ * function to take raw key data and convert it * into ascii chars **************************************************/ int toasc(code,local) unsigned int code; int local; { static int ctrl = FALSE; static int shift = FALSE; static int capsl = FALSE; char c; static char keys[75] = { '`','1','2','3','4','5','6','7','8','9','0','-' , '=','\\', 0, '0','q','w','e','r','t','y','u','i','o' , 'p','[',']', 0, '1','2','3','a','s','d','f','g','h' , 'j','k','l',';','\'', 0, 0, '4','5','6', 0, 'z','x','c','v', 'b','n','m',44,'.','/', 0, '.','7','8','9',' ',8, '\t',13,13,27,127,0,0,0,'-' } ; switch ( code ) { case 98: capsl = TRUE; c = 0;break; case 226: capsl = FALSE;c = 0;break; case 99: ctrl = TRUE; c = 0;break; case 227: ctrl = FALSE; c = 0;break; case 96: case 97: shift = TRUE; c = 0;break; case 224: case 225: shift = FALSE;c = 0;break; case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: case 0x59: c = 0; if (shift) sendstring(p_F[code - 0x50]); else sendstring(p_f[code - 0x50]); break; case 0x0f: c=0; sendstring("\033Op"); break; case 0x1d: c=0; sendstring("\033Oq"); break; case 0x1e: c=0; sendstring("\033Or"); break; case 0x1f: c=0; sendstring("\033Os"); break; case 0x2d: c=0; sendstring("\033Ot"); break; case 0x2e: c=0; sendstring("\033Ou"); break; case 0x2f: c=0; sendstring("\033Ov"); break; case 0x3d: c=0; sendstring("\033Ow"); break; case 0x3e: c=0; sendstring("\033Ox"); break; case 0x3f: c=0; sendstring("\033Oy"); break; case 0x43: c=0; sendstring("\033OM"); break; case 0x4a: c=0; sendstring("\033Ol"); break; case 0x5f: c=0; sendstring("\033Om"); break; case 0x3c: c=0; sendstring("\033On"); break; case 0x4c: c=0; sendstring("\033[A"); break; case 0x4d: c=0; sendstring("\033[B"); break; case 0x4e: c=0; sendstring("\033[C"); break; case 0x4f: c=0; sendstring("\033[D"); break; default: if (code < 75) c = keys[code]; else c = 0; } /* add modifiers to the keys */ if (c != 0) { if (shift) { if ((c <= 'z') && (c >= 'a')) c -= 32; else switch( c ) { case '[': c = '{'; break; case ']': c = '}'; break; case '\\': c = '|'; break; case '\'': c = '"'; break; case ';': c = ':'; break; case '/': c = '?'; break; case '.': c = '>'; break; case ',': c = '<'; break; case '`': c = '~'; break; case '=': c = '+'; break; case '-': c = '_'; break; case '1': c = '!'; break; case '2': c = '@'; break; case '3': c = '#'; break; case '4': c = '$'; break; case '5': c = '%'; break; case '6': c = '^'; break; case '7': c = '&'; break; case '8': c = '*'; break; case '9': c = '('; break; case '0': c = ')'; break; default: break; } } else if (capsl && (c <= 'z') && (c >= 'a')) c -= 32; } if (ctrl) { if (c >= '`' && c <= 127) c -= 96; else if (c >= '@' && c <= '_') c -= 64; } if (c != 0 && (!local)) sendchar(c); return((int)c); } SHAR_EOF cat << \SHAR_EOF > xmodem.c /************************************************************* * vt100 terminal emulator - XMODEM protocol support * * 860823 DBW - Integrated and rewrote lots of code * 860815 Steve Drew: readchar inproved with real timeouts * v2.0 860809 DBW - Major rewrite * v1.1 860720 DBW - Switches, 80 cols, colors, bug fixes * v1.0 860712 DBW - First version released * *************************************************************/ #define MODULE_XMODEM 1 #include "vt100.h" /* forward declarations for LATTICE */ void sendstring(); void sendchar(); /************************************************************ * Send a string (using sendchar below) ************************************************************/ void sendstring(s) char *s; { char c; while ((c = *s++) != '\000') sendchar(c); } /**************************************************************/ /* send char and read char functions for the xmodem function */ /************************************************************/ void sendchar(ch) int ch; { rs_out[0] = ch & 0xFF; DoIO(Write_Request); } int readchar() { int rd,ch; Timer.tr_time.tv_secs = ttime; Timer.tr_time.tv_micro = 0; SendIO((char *) &Timer.tr_node); rd = FALSE; while (rd == FALSE) { Wait((1L << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit) | ( 1L << mywindow->UserPort->mp_SigBit) | ( 1L << Timer_Port->mp_SigBit)); if (CheckIO(Read_Request)) { WaitIO(Read_Request); ch=rs_in[0]; rd = TRUE; BeginIO(Read_Request); } if (NewMessage=(struct IntuiMessage *)GetMsg(mywindow->UserPort)) { if ((NewMessage->Class == RAWKEY) && (NewMessage->Code == 69)) { AbortIO((char *) &Timer); Wait (1L << Timer_Port->mp_SigBit); if (want_message) emits("\nUser aborted transfer\n"); timeout = USERABORT; return('\0'); } continue; } if (rd == FALSE && CheckIO(&Timer)) { if (want_message) emits("\nTimeout waiting for character\n"); timeout = TIMEOUT; return('\0'); } } /* end while */ AbortIO((char *) &Timer); Wait (1L << Timer_Port->mp_SigBit); timeout = GOODREAD; return(ch & 0xFF); } /**************************************/ /* xmodem send and recieve functions */ /************************************/ int XMODEM_Read_File(file) char *file; { int firstchar, sectnum, sectcurr, sectcomp, errors, errorflag; unsigned int checksum, j, bufptr; char numb[10]; bytes_xferred = 0L; ttime = TTIME_SHORT; want_message = TRUE; /* tell readchar to print any error msgs */ if ((fd = creat(file, 0)) < 0) { emits("Cannot Open File\n"); return FALSE; } else emits("Receiving File\n\nType to abort transfer\n"); sectnum = errors = bufptr = 0; sendchar(NAK); firstchar = 0; while (firstchar != EOT && errors != ERRORMAX) { errorflag = FALSE; do { /* get sync char */ firstchar = readchar(); if (timeout != GOODREAD) { if (timeout == USERABORT || errors++ == ERRORMAX) return FALSE; } } while (firstchar != SOH && firstchar != EOT); if (firstchar == SOH) { emits("Getting Block "); sprintf(numb, "%d", sectnum); emits(numb); emits("..."); sectcurr = readchar(); if (timeout != GOODREAD) return FALSE; sectcomp = readchar(); if (timeout != GOODREAD) return FALSE; if ((sectcurr + sectcomp) == 255) { if (sectcurr == ((sectnum + 1) & 0xff)) { checksum = 0; for (j = bufptr; j < (bufptr + SECSIZ); j++) { bufr[j] = readchar(); if (timeout != GOODREAD) return FALSE; checksum = (checksum + bufr[j]) & 0xff; } if (checksum == readchar() && timeout == GOODREAD) { errors = 0; sectnum++; bufptr += SECSIZ; bytes_xferred += SECSIZ; emits("verified\n"); if (bufptr == BufSize) { if (write(fd, bufr, BufSize-128) == EOF) { emits("\nError Writing File\n"); return FALSE; } bufptr = 128; for (j = 0; j < 128; j++) bufr[j] = bufr[(BufSize-128)+j]; } sendchar(ACK); } else { errorflag = TRUE; if (timeout == USERABORT) return FALSE; } } else { /* got a duplicate sector */ if (sectcurr == (sectnum & 0xff)) { /* wait until we time out for 5secs */ do { readchar(); } while (timeout == GOODREAD); if (timeout == USERABORT) return FALSE; emits("\nReceived Duplicate Sector\n"); sendchar(ACK); } else errorflag = TRUE; } } else errorflag = TRUE; } if (errorflag == TRUE) { errors++; emits("\nError\n"); sendchar(NAK); } } /* end while */ if ((firstchar == EOT) && (errors < ERRORMAX)) { sendchar(ACK); while (bufptr > 0 && (bufr[--bufptr] == 0x00 || bufr[bufptr] == 0x1A)) ; write(fd, bufr, ++bufptr); close(fd); return TRUE; } return FALSE; } int XMODEM_Send_File(file) char *file; { int sectnum, bytes_to_send, size, attempts, c; unsigned checksum, j, bufptr; char numb[10]; bytes_xferred = 0; ttime = TTIME_LONG; want_message = TRUE; /* tell readchar to print any error msgs */ if ((fd = open(file, 0)) < 0) { emits("Cannot Open Send File\n"); return FALSE; } else emits("Sending File\n\nType to abort transfer\n"); attempts = 0; sectnum = 1; /* wait for sync char */ j=1; while (((c = readchar()) != NAK) && (j++ < ERRORMAX)) if (timeout == USERABORT) return(FALSE); if (j >= (ERRORMAX)) { emits("\nReceiver not sending NAKs\n"); return FALSE; } while ((bytes_to_send = read(fd, bufr, BufSize)) && attempts != RETRYMAX) { if (bytes_to_send == EOF) { emits("\nError Reading File\n"); return FALSE; } bufptr = 0; while (bytes_to_send > 0 && attempts != RETRYMAX) { attempts = 0; emits("Block "); sprintf(numb, "%d ", sectnum); emits(numb); do { emits("."); sendchar(SOH); sendchar(sectnum); sendchar(~sectnum); checksum = 0; size = SECSIZ <= bytes_to_send ? SECSIZ : bytes_to_send; bytes_to_send -= size; for (j = bufptr; j < (bufptr + SECSIZ); j++) if (j < (bufptr + size)) { sendchar(bufr[j]); checksum += bufr[j]; } else sendchar(0); sendchar(checksum); attempts++; c = readchar(); if (timeout == USERABORT) {emits("\n"); return FALSE;} } while ((c != ACK) && (attempts != RETRYMAX)); bufptr += size; bytes_xferred += size; emits(" sent\n"); sectnum++; } } close(fd); if (attempts == RETRYMAX) { emits("\nNo Acknowledgment Of Sector, Aborting\n"); return FALSE; } else { attempts = 0; do { sendchar(EOT); attempts++; } while ((readchar() != ACK) && (attempts != RETRYMAX) && (timeout != USERABORT)) ; if (attempts == RETRYMAX) emits("\nNo Acknowledgment Of End Of File\n"); } return TRUE; } SHAR_EOF # End of shell archive exit 0