dillon@CORY.BERKELEY.EDU (Matt Dillon) (04/27/87)
DTERM 1.01 (Beta) BETA BETA BETA BETA BETA BETA BETA REQUEST FOR COMMENTS REQUEST FOR COMMENTS REQUEST FOR COMMENTS Specifically, what other primitives should I add to the console device to support emulation of other terminals (e.g. graphics commands?). NOTE: Currently, there is not enough low-level support to be able to even partially emulate a VT100. The emulation choices you have are for (A) Z29, (B) ANSI, or (C) your own devising. For those of you who log into 4.2/3 (and many other systems), note that the termcap for a SUN is actually an extended ANSI specification, compatible with the Amiga's console driver. (I) Overview of Features (II) Command line options (III) Command Language (IV) State Machine Commands (including carrier state change autovectors) (V) Menu Commands (VI) Mapping Commands (VII) Serial Commands (including console init autovector) (VIII) Misc. other commands (including XMODEM commands) (X) SAMPLE S:DTERM.INIT FILE (XI) SAMPLE Z29 emulation init file. (I) OVERVIEW OF FEATURES note: SENDFILE is a command to send a raw data file over the modem without using any protocal and without passing the data through any maps. USER PROGRAMMABLE DATA TRANSLATIONS: KeyMap KEYMAP DataMap DATAMAP ******************************************************************* KEYBOARD---->KEYMAP---->SERIALOUT | V [full duplex]? YES -> done NO | (HALF, HOST, or HMONITOR duplex) | | |>------>WINDOW |>------>CAPTURE (if capture mode) \>------>TOCLI (if remote on & duplex == HMONITOR) SERIALIN--->DATAMAP---->WINDOW | |>------>WINDOW |>------>CAPTUREFILE (if capture mode) |>------>TOCLI (if remote on) |>------>STATE_MACHINE \>------>SERIALOUT (if HOST or HMONITOR duplex) FROMCLI---------->KEYMAP---------->SERIALOUT | [HMONITOR duplex]? ---> NO, stop YES V | \---->DATAMAP--------->WINDOW | \----->CAPTUREFILE (if capture mode) SENDFILE-------------------------->SERIALOUT DIAGNOSTICMESSAGES---------------->LOGFILE (when log is on) When in XMODEM protocol, everything is suspended and the following applies. XMODEM protocol is entered explicitly with XRECEIVE and XTRANSMIT commands. XTRANSMIT<------------------------>SERIALIN/OUT (when sending XMODEM) XRECEIVE <------------------------>SERIALIN/OUT (when recv. XMODEM) DTERM is a terminal program for use with an Amiga. DTERM is not meant for the weak and helpless. I consider the following features: (1) Small executable (2) State Machine allowing you to build any automatic control structure you wish (from auto-redial, sequence dialing, to auto-logon). (3) Intelligent Data Mapping (4) Intelligent Keyboard Mapping (5) Dynamic Menus (user-buildable) (6) somewhat intelligent command language (DME-like, but with extensions, and a different set of commands of course). (7) Asyncronous writes in capture mode (it isn't not jerky), and block pre-fetch/asyncronous writes in the XMODEM transfer protocol. (8) duplex control, can SLAVE a CLI to the serial port. A consequence of (3) and (4) means that an intelligent person can setup maps to effectively emulate most other terminals. (II) COMMAND LINE OPTIONS DTERM [-flags] [file1...filen] -x -Use XON/XOFF protocol -f -Use RAD_BOOGIE (see serial documentation) -7 -Use 7Wire protocol -e -Use Exclusive Access -b -Use BORDERLESS window. Assume person's CONAI vector will handle initializing the console device's window parameters. default: SHARED access, no protocol file1...filen: A list of script files to execute on startup. If no files specified, S:DTERM.INIT is sourced. (III) COMMAND LANGUAGE The command language is based on the DME text editor. For those of you familar with DME, the modifications to the basic structure are as follows: (read the following only if you are familar with DME!!) ^c = control-c, for embedding control characters in a source file \nnn = octal escape code \f = a forward single quote (good for first pass-thru only) \b = a back single quote (good for first pass-thru only) COMMAND LANGUAGE: A command has a certain number of arguments. You can string any number of commands together because DTERM knows exactly how many arguments each command takes. Thus: baud 1200 parity even bits 8 stop 1 will set the program into 1200 baud, even parity, wordlength of 8, and 1 stop bit. Note that arguments are space delimited. A problem occurs when you want a given argument to contain several words. You can get around this by surrounding the argument with a SINGLE-BACK-QUOTE, SINGLE-FORWARD-QUOTE `' pair. Example: conwrite `hello this is a test' conwrite sorry A set of back-forward single quotes is stripped every time a string is passed through the command interpreter. This represents a problem only if some command's argument(s) will be sent through the command interpreter at some later date. The CONAI command is a good example. The argument you specify to the CONAI command is executed whenever the console gets reset, allowing you to automatically reconfigure the console device. Since a backquote-quote pair will be stripped the second time through (once when you gave the CONAI command, and once when the CONAI command's argument is executed): conai `conwrite `my console has been reset!' conwrite bah' The outer set forces CONAI to recognize the entire rest of the line as it's single argument. The inner set forces the CONWRITE command to recognize the 5 words `my console has been reset!' as its single argument when it gets executed some time in the future. Text sent to the modem must be enclosed by yet another backquote-quote pair to differentiate it from a command: conwrite hello -writes hello to the console device. `conwrite hello' -sends the string "conwrite hello" over the modem This can be confusing. Here is a more complex example using CONAI: conai `baud 2400 `this is sent over the modem at 2400 baud'' (not that you would want to put a serial control command in a console reset vector... the console gets reset whenever you resize its window.) USUALLY, YOU WANT TO PUT THE FOLLOWING IN S:DTERM.INIT: conai `conwrite `^[[20l'' Almost every terminal in existance uses LF=LF rather than LF=CRLF, which is what the above will accomplish. OVERVIEW OF COMMANDS. See specific sections for more information. DUPLEX full/half/host/hmonitor duplex mode BAUD n Set Baud PARITY even/odd/mark/space/off Set Parity STOP n Set Stop bits BITS n Set Wordlength DELAY mS Delay X mS DD Delay 1/10 sec SOURCE file script RESIZE cols rows resize window SMADD state newstate matchstring command add state SMREM state.uniq remove a specific entry SMREMSTATE state remove entire state SMCLEAR remove ALL states SMGOTO state goto a state SMONCD command On Carrier Detect SMONCL command On Carrier Lost SMONPUCD command CD on initial power up SMLIST display SM info DATAMAP from to map incomming data DATAUNMAP from unmap a map DATACLEAR clear all datamaps KEYMAP from to (NOT like DME) map outgoing keystrokes KEYUNMAP from unmap a map KEYCLEAR clear all datamaps MENUADD menuname itemname command add a menu entry MENUDEL menuname itemname delete a menu entry MENUCLEARCOL menuname clear a menu header MENUCLEAR clear entire menu CONAI command On Console Init CONWRITE string write to console.device CAPON file capture to file CAPOFF close capture LOGON file log error/status msgs to file LOGOFF no log SEND file send from file SENDABORT abort send XRECEIVE file XMODEM receive XTRANSMIT file XMODEM transmit SLAVE on/off remote CLI SETSLAVE command set slave command default is a NEWCLI. COMENTRY manual command entry COMPROMPT promptstring latter w/prompt (IV) STATE MACHINE COMMANDS The state machine looks at every sub-string comming over the serial line for matches against the matchstring of all entries in the current state. Here is an example script to automatically set DTERM's baud rate to a modem's new baud rate after it connects to some remote machine: template: SMADD state newstate matchstring command ########### smclear smadd a b `CONNECT 2400^m^j' `baud 2400 delay 2000 `^m'' smadd a b `CONNECT 1200^m^j' `baud 1200 delay 2000 `^m'' smadd a b `CONNECT^m^j' `baud 300 delay 2000 `^m'' smadd a b `CONNECT ^m^j' `baud 300 delay 2000 `^m'' smgoto a smoncl `smgoto a' ########### In this case, all entries are in state 'a'. While the state machine is in state 'a', any of these messages will cause it to execute the specified command and then go into state 'b'. Note that we have setup the automatic carrier-lost vector to go back into state 'a' on carrier lost. Statenames are in ascii, and need not be a single character. When you remove a state with SMREMSTATE, you are removing all the entries in that state. The state machine is bypassed whenever it is placed in a state which doesn't exist... `SMGOTO idontexist' SMADD state[.uniq] newstate matchstring command add state SMREM state.uniq remove an entry SMREMSTATE state remove entire state SMGOTO state goto a state SMONCD command On Carrier Detect SMONCL command On Carrier Lost SMONPUCD command CD on power up. SMCLEAR Remove ALL states SMLIST display SM info Note: SMONPUCD means 'if the carrier is active when this modem program starts up'. Usually this means that you exited the modem program then re-ran it, and that you are already logged into the machine. You can thus have the command be, say, an SMGOTO to your 'online' state. HINTS: You could, of course, put all your matches into a single state, but this could be disastorous if any of those strings occured accidently while you were connected to some host. Thus, you should breakup the state-sets logically. Definition of state-set: A state-set is a single state containing several match->command entries. E.G. The example above has a single state-set named 'a' with 4 entries. -Have a state-set that you SMONCL to (SMONCL `smgoto state') for your 'off line' activity... e.g. dialing, re-dialing, etc... -Have a base state-set for your 'connected but not yet logged in' state which then dispatches to other state-sets when it determines what your logging in to. -Once you are completely logged in, place the state machine in a non-existant or minimal state to prevent accidental matches from occuring and to make DTERM run faster (though the slowdown is not noticeable at 2400 baud!). The state commands are usually placed in the S:DTERM.INIT file. IDENTIFYING STATES FOR REMOVAL WITH SMREM. You can identify an entry in a state by giving it a unique name state[.name]. example: smadd a b match1 command1 smadd a.special b match2 command2 smrem a.special -remove a.special only. NOTE: Both `a' and `a.special' are considered in state `a'. The .special is only a way of identifying an entry so you can remove it later. (V) MENU COMMANDS The Menu commands allow you to build user-defined menu's. These are usually placed in S:DTERM.INIT also. You should make a menu entry for the COMENTRY command always to allow you to get into manual command-entry mode. Here is an example: menuadd phone cory ``^j' dd `^matdt6420074^m'' menuadd phone cogsci ``^j' dd `^matdt6420713^m'' menuadd phone portsel ``^j' dd `^matdt6436545^m'' menuadd phone fidonet ``^j' dd `^matdt6599169^m'' menuadd phone bbs2 ``^j' dd `^matdt5952479^m'' menuadd phone wincrc ``^j' dd `^matdt8454812^m'' menuadd phone amwest ``^j' dd `^matdt3557162^m'' menuadd phone amconn ``^j' dd `^matdt5627097^m'' menuadd phone bbsJC ``^j' dd `^matdt9617250^m'' menuadd ctl comentry `comentry' menuadd ctl 7bit-even `bits 7 parity even' menuadd ctl 8bit-none `bits 8 parity off' menuadd window 80x24 `resize 80 24' menuadd window 80x25 `resize 80 25' menuadd emulate none `dataclear keyclear' menuadd emulate z29 `source emulate:z29.termcap' menuadd emulate vt100 `source emulate:vt100.termcap' (VI) MAPPING COMMANDS Arbitrary keyboard and data mapping is accomplished with the DATAMAP and KEYMAP commands. Both have the same syntax with the exception that one applies to the mapping of incomming data, and the other applies to the mapping of keys. XXXMAP from to DTERM's terminal window IS the Amiga's console device with some additional features: \200 Insert Mode OFF 0x80 \201 Insert Mode ON 0x81 \202 Save Cursor Position 0x82 \203 Restore Cursor Position 0x83 \204 Back Tab 0x84 The easiest mapping to understand is an ascii-to-ascii map: (map esc-A to esc-left_bracket-A) DATAMAP ^[A ^[[A The control sequence introducer on the FROM string is '$'. Thus, to get a '$' as part of the from string, you need to say '$$'. $c stands for an arbitrary character, and $d stands for an arbitrary ascii-numeric string. When the actual map occurs, both are converted to numbers and placed into an array for further manipulation by the TO string. FROM STRING CONTROL SPECIFIERS: $c arbitrary character $d arbitrary ascii-numeric str. TO STRING CONTROL SPECIFIERS: $N[+/-OFFSET]c $N[+/-OFFSET]d The TO control specifier is a bit more complex. You pick an array entry with $N (starting at 0), add an optional offset value to it, then plot it down as either a single character, or an ascii-decimal string. Example: (Convert Z29 cursor move sequence to ANSI cursor move sequence) datamap ^[Y$c$c ^[[$0-31d;$1-31dH ^[Y8! -> ^[[25;2H (Map escape X c1 c2 to d2 d1) datamap ^[X$c$c $1d.$0d ^[XAB -> 66.65 datamap ^[X$c $0-10d ^[XA -> 55 datamap ^[X$c $0+10d ^[XA -> 75 datamap ^[X$c $0+1c ^[XA -> B See the provided emulation files (not quite complete working, but pretty close) for more examples. WITHHOLDING DELAYS: If you do a keymap, say ^[X -> hello, and then type ESC, you will note that nothing got sent over the modem. DTERM withholds anything left unresolved until it is either resolved, or found not to be mapped. Thus: ESC (nothing sent) X (hello sent) ESC (nothing sent) Y (ESC Y sent) MAPS OVERRIDING OTHER MAPS: Later maps can override earlier ones. Thus, if you have two maps: KEYMAP ^[a haha KEYMAP ^[$c bobo The ^[$c map will ALWAYS be executed, even if you type ^[a. Rightly, you should have the order reversed: KEYMAP ^[$c bobo KEYMAP ^[a haha Thus you can MAP something general (using $c) to nothing, and then MAP some exceptions to the rule. (VII) SERIAL COMMANDS BAUD, PARITY, STOP, BITS. Examples: BAUD 2400 PARITY off BITS 8 STOP 1 NOTE: if using the -f flag (RAD_BOOGIE), the serial device makes some assumptions on the parity and wordsize. Read the serial.device docs for more information. (VIII) MISC OTHER COMMANDS The remaining commands are: DD Delay for a 1/10 of a second. DELAY N Delay for N milliseconds. `DD 1000' will delay for a second SOURCE file Source a script file. The script file usually contains state machine entries, menu additions, terminal emulation mappings, etc... SOURCE s:dterm.init RESIZE cols rows Attempt to resize the window on the current screen. No window repositioning is done. You might have to move the window to the upper-left hand corner before resizing depending. If the screen is big enough, a bordered window is used. If the screen is barely big enough, a borderless window is used. If the screen isn't big enough for even a borderless window, you get an error message. RESIZE 80 24 RESIZE 76 24 Your CONAI command is automatically executed after the window is resized. CONAI command The command is executed immediate, and also whenever the console device gets reset. This occurs whenever a window is resized. Usually, CONAI is set to: conai `conwrite `^[[20l'' CONWRITE string Write a string directly to the console device. Does not go through the serial.device. Usually used to initialize the console. CAPON file Begin capture mode to a file. If the file already exists, it is APPENDED to. CAPOFF End capture mode to a file DUPLEX HALF/FULL/HOST/HMON -FULL: (DEFAULT) keystrokes are not normally displayed on terminal screen after going through the keymap. -HALF: keystrokes in terminal window are echo'd on terminal screen after going through the keymap. -HOST: keystrokes are echo'd on terminal screen after going through keymap. Additionally, any data comming over the serial port is echo'd back to the sender as well as displayed. -HMON: same as HOST mode, but if SLAVE is on (for SLAVED CLI), keystrokes from the terminal window are also sent to the CLI. LOGON file Log messages to a file.. appends to the file. Anything that is displayed on your console by DTERM (not incomming serial data) is logged. LOGOFF Stop logging messages SEND file Send a file over the modem by simply COPYing it to the serial device. SENDABORT Abort a Send (Sends are done semi-asyncronously). XRECEIVE file XMODEM protocol receive to file. Basic XMODEM protocol using a checksum. The file is written to asyncronously and thus you need not specify the RAM: disk for optimal performance. If the file previously exists, XRECEIVE will attempt to find a function of that filename which does not exist. (e.g. file0, file1, file2...). This allows automated downloading. XTRANSMIT file XMODEM protocol send from a file. Basic XMODEM protocol using a checkdsum. The file blocks are pre-fetched while the previous block is being sent asyncronously, and thus you need not copy the file to the RAM: disk before sending. COMENTRY Begin manual command entry. Hit return on a blank line to end manual entry of commands. COMPROMPT arg Enter COMENTRY mode with 'arg' already typed for you... allows making menu options which prompt for thing. SETSLAVE executecommand Set the command which is Execute()d when SLAVE mode is turned on. The default is 'NEWCLI'. The command will be executed with a single argument which will be the file it is supposed to do ALL communication with the modem program through. The Execute() is expected to return immediately, so you should specify something like: SETSLAVE `run myslave' The slave program MUST open the specified file with modes 1005. The slave program does it's READs and WRITEs to the SAME FILE HANDLE. The latest version of my PIPE: program must be mounted in your system for this to work. NOTE: The filename passed to your slave program looks something like this: PIPE:somename/t Usually, you'll want to append a signal to this (make it /ts#, for instance, where # is a signal number you have allocated) to give you more control. READ THE DOCS FOR A PIPE TO UNDERSTAND THE MEANING! Look at the flow diagrams at the beginning to see how data flows to and from the slave program. IT IS NOT RECOMMENDED THAT YOU IMPLEMENT TRANSFER PROTOCOLS WITH SLAVE PROGRAMS. This is because the data would have to travel through two processes before ever going out the serial port, causing unforgivable delays in a transfer protocol. The slaving is still in a very experimental state. SLAVE on/off ACTIVATE SLAVE CLI. my latest PIPE: device must be mounted for this to work. NOTE: When you turn SLAVE off, the CLI will still be connected to the PIPE. To disconnect the CLI from the pipe, you must send an ENDCLI to the CLI. This command starts up a new CLI on the pipe if none currently is attached. -EFFECTS: Any data received from the serial port is sent to the CLI after going through the datamap. Any data output from the CLI is sent to the serial port after going through the keymap. (X) SAMPLE S:DTERM.INIT FILE. This is the DTERM.INIT file that I use. Needless to say, I've changed all references to specific machine names, user names, and passwords to gobbly gook. ####################################################################### # Hash is a comments introducer, and must be the first character on # # a line # # # # DTERM.INIT # # # ####################################################################### baud 2400 parity even bits 7 smclear smadd a a `comp1' `baud 2400 parity even bits 7 `^j^matdt5551111^m'' smadd a a `comp2' `baud 2400 parity even bits 7 `^j^matdt5552222^m'' # NOTE: Sends a return 2 seconds after connect. smadd a a `CONNECT 2400^m^j' `baud 2400 delay 2000 `^m'' smadd a a `CONNECT 1200^m^j' `baud 1200 delay 2000 `^m'' smadd a a `CONNECT^m^j' `baud 300 delay 2000 `^m'' smadd a a `CONNECT ^m^j' `baud 300 delay 2000 `^m'' # Handle a port-selector smadd b b Request: `dd `cory^m'' # Figure out which computer it is by it's header message smadd b cl comp1 `' smadd b cg comp2 `' # A BBS! smadd b cbbs `name:' ``Matthew Dillon^m'' smadd cbbs cbbs `Password:' `delay 1000 `mypassword^m'' smadd cbbs cbbs `[Y,n]:' `delay 1000 `^m'' smadd cl cl1 login: `dd `dillon^m'' smadd cl1 cl1 Password: `dd `mypassword^m'' smadd cl1 cl incorrect `' smadd cl1 online (z29) `dd `vt100^m'' smadd cg cg1 login: `delay 2000 `myfriend^m'' smadd cg1 cg1 Password: `dd dd dd dd `hispassword' dd `^m'' smadd cg1 cg incorrect `' # For UNIX systems, TERM = sun (Latest ANSI with enhancements) # Compatible with the Amiga's CONSOLE.DEVICE # My login defaults to a Z29... smadd cg1 online (z29) `dd `sun^m'' #smadd online online Password: ``mypassword^m'' smgoto a smoncl `smgoto a delay 1000 baud 2400' smoncd `smgoto b' smonpucd `smgoto online' menuadd phone fidonet ``^j' dd `^matdt6599169^m'' menuadd phone bbs2 ``^j' dd `^matdt5952479^m'' menuadd phone wincrc ``^j' dd `^matdt8454812^m'' menuadd phone amwest ``^j' dd `^matdt3557162^m'' menuadd phone amconn ``^j' dd `^matdt5627097^m'' menuadd phone bbsJC ``^j' dd `^matdt9617250^m'' menuadd ctl comentry `comentry' menuadd ctl 7bit-even `bits 7 parity even' menuadd ctl 8bit-none `bits 8 parity off' menuadd ctl `redial on' `smadd a a `BUSY^m^j' `delay 30000 `a/''' menuadd window 80x24 `resize 80 24' menuadd window 80x25 `resize 80 25' menuadd emulate none `dataclear keyclear' menuadd emulate z29 `source emulate:z29.termcap' conai `conwrite `^[[20l'' ####################################################################### # # # END DTERM.INIT # # # ####################################################################### (XI) SAMPLE Z29 EMULATION INIT FILE (not complete, but it gives you the idea). ###################################################################### # EMULATE:Z29.TERMCAP # # NOTE: assumes your terminal window is 25-lines # ###################################################################### # Z29 termcap # :am has automatic margins # :bc=\ED backspace if not ^H datamap ^[D \233D # :bt=\E- backtab datamap ^[- \204 # :do=^J down one line # :al=\EL add new blank line datamap ^[L \233L # :le=^H cursor left # :bs terminal can BS with ^H # :cd=\EJ clear to end of display datamap ^[J \233J # :ce=\EK clear to end of line datamap ^[K \233K # :cl=\EE clear screen and home datamap ^[E \2331;1H\233J # :cm=\EY%+\040%+\040 cursor move datamap ^[Y$c$c \233$0-31d;$1-31dH datamap ^[Y8$c \23325t\23325;$0-31dH # :co#80 #cols # :dc=\EN delete char datamap ^[N \233P # :dl=1*\EM delete line datamap ^[M \233M # :ei=\EO end insert mode datamap ^[O \200 # :ho=\EH home cursor datamap ^[H \233H # :im=\E@ enter insert mode datamap ^[@ \201 # :li#24 #lines # :mi safe to move while in insert mode # :nd=\EC cursor right datamap ^[C \233C # :as=\EF start alternate char set datamap ^[F `' # :ae=\EG end alternate char set datamap ^[G `' # :ms safe to move in standout mode # :pt has hardware tabs # :sr=\EI scroll text down datamap ^[I \233T # :se=\Eq end standout mode datamap ^[q `' # :so=\Ep begin standout mode datamap ^[p `' # :up=\EA cursor up datamap ^[A \233A datamap ^[B \233B # :vs=\Ex4 cursor very visible datamap ^[x4 `' # :ve=\Ey4 cursor normal datamap ^[y4 `' # :kb=^H sent by backspace key # :ku=\EA up key keymap \233A ^[A # :kd=\EB down key keymap \233B ^[B # :kl=\ED left key keymap \233D ^[D # :kr=\EC right key keymap \233C ^[C # :kh=\EH home key # :kn#1 # function keys # :k0=\E~ Function key 0 keymap \2330~ ^[~ # :l0=HOME labels on function keys # :k1=\ES function keys keymap \2331~ ^[S # :k2=\ET keymap \2332~ ^[T # :k3=\EU keymap \2333~ ^[U # :k4=\EV keymap \2334~ ^[V # :k5=\EW keymap \2335~ ^[W # :k6=\EP keymap \2336~ ^[P # :k7=\EQ keymap \2337~ ^[Q # :k8=\ER keymap \2338~ ^[R # :k9=\E0I keymap \2339~ ^[0I # :es escape allowed on status line # :hs has extra 'status' line # :ts=\Ej\Ex5\Ex1\EY8%+\040\Eo GO status line col N datamap ^[j \202 datamap ^[x1 `' datamap ^[x5 \23325t datamap ^[o `' # :fs=\Ek\Ey5 return from status line # **big hack datamap ^[k \203\23324t datamap ^[y5 \23324t # :ds=\Ey1 disable status line datamap ^[y1 \23324t # :us=\Es8 start underscore mode datamap ^[s8 `' # :ue=\Es0 end underscore mode datamap ^[s0 `' # # END EMULATE:Z29.TERMCAP #