TCJ45.WS A Mex-Plus Script for Using PC-Pursuit Jay Sage Last time we gave you a pretty thorough presentation of the script¨ language from the MEX-Plus telecommunications program. However, as¨ necessary as such documentation is, it does not really teach one how to make¨ effective use of the language. So this time we will present as a teaching¨ example the script that I use for almost all my telecommunication work. It¨ is the most complex script that I have ever written, illustrates many¨ techniques, and might be very useful to many of you as well. This script is far from perfect. Every time I work with MEX-Plus I learn¨ something more about it, and that was a large part of my motivation for¨ writing these two columns. As usual, I hope that some astute readers will¨ notice ways to improve on my script. More MEX Commands Before getting into the script itself, I have a few items to add to the¨ discussion from last time. First, I forgot to mention one extremely¨ important MEX command; second, just today I discovered some more¨ undocumented commands that appear to be quite interesting. The WAIT Command The WAIT command is one of MEX's most important commands. It allows MEX¨ to monitor the character stream coming back from the remote system and to¨ take various actions depending on what it sees. There are four variants of¨ the command: WAIT DATE, WAIT TIME, WAIT SILENCE, and WAIT STRING. The first two forms cause the script to pause until a specified date or¨ time arrives. Obviously, you must have a real-time clock and a MEX clock¨ module installed for these commands to work. The command forms are: WAIT DATE mm/dd WAIT TIME hh:mm These commands would be useful for a script to automatically place a call¨ during the middle of the night when phone rates are lower The WAIT SILENCE command waits until no characters have been received¨ from the modem for a specified time interval. This is one way to infer that¨ the remote system has finished what it was doing and is ready for a command¨ from you. The syntax is WAIT SILENCE [time] The most powerful of the WAIT commands is WAIT STRING, whose full syntax¨ is WAIT STRING [time] string1 [string2 string3 string4] This command takes from one to four string expressions and an optional¨ wait time, which otherwise defaults to values set by STAT parameters. The¨ command terminates as soon as one of the strings is detected or the time¨ limit expires. The VALUE variable tells you the result. It will be 0 if¨ the time limit was reached or 1, 2, 3, or 4 depending on which string was¨ matched. You will see a number of examples of the use of this command in my¨ PC-Pursuit script. Undocumented Commands MEX has quite a number of undocumented commands. These can be discovered¨ by doing a memory dump of MEX.COM and looking for the command dispatch¨ table. Scanning programs' command tables to see what goodies might have¨ been built into them that the authors -- for one reason or another --¨ decided not to tell you about is a great sport. I will mention only a few¨ of the MEX commands I discovered this way. First, there are some commands that are just alternate names for¨ documented functions. For example, there is a RENAME command that vectors¨ to the same code that the REN command does. Since, as I mentioned last time, there seemed to be a paucity of way to¨ get out of MEX (only about six commands!), I was quite relieved to discover¨ the command ABORTMEX, which appears to offer yet another way! Actually, I¨ have a recollection of having seen that command somewhere in the¨ documentation, but it is not listed in the index and I cannot find it again. ¨ From examining the dispatch vectors, I can tell that ABORTMEX is not the¨ same thing as CPM, EXIT, QUIT, and so on, but it seems to do the same thing. One command that I think will prove quite useful is the PAUSE command. ¨ Its syntax appears to be like that of the undocumented PRINT. Whatever text¨ comes after it is echoed to the screen, and the script then pauses until any¨ key is pressed. The MEM command looked as though it was going to be quite useful, as it¨ displays the status of MEX's memory buffer. The trouble is, I have not been¨ able to figure out what buffer this is! I started a capture buffer, and MEM¨ still showed the same values and reported that none of the buffer was in¨ use. Then I put the command in a script file, thinking it might report the¨ status of the script buffer. Alas, the report was still the same. Perhaps¨ this is just a command that was never fully coded. All I can say is that¨ the buffer size reported does depend on the size of one's TPA. Another very interesting command is WIN. Its name suggested that it¨ created some kind of window, and indeed it does. It is probably not¨ documented because it does not seem to work completely correctly. I entered¨ the command WIN 5 5 12 75 and MEX drew a partial box of the sort that "BOX 5 5 12 75" would have and¨ then puts its prompt at the upper left corner of the window. After that,¨ screen output was restricted to the lines in the window, but the lateral¨ limits of the window were not observed; text still ran across the full width¨ of the screen. The STAT command would fill just the window and then wait¨ for a keypress to continue. Of course, I did my tests from the command¨ line, and WIN may act differently if invoked from a script file. The "@" command cursor addressing could still take one anywhere on the¨ screen. Thus, it looks as though the WIN command might be useful in some¨ special cases where one wants to keep certain status information on the¨ screen. The window could be set to the last 20 lines on the screen, and¨ status information could be written using "@ SAY" to the regions outside the¨ window. Another command whose function I thought I could guess was FLUSH. I¨ assumed that it flushes the contents of a buffer, perhaps the capture¨ buffer. However, I tried it with a capture buffer, and nothing seemed to¨ happen. There must be something more subtle about it. Finally, there are the commands DUPE, RESTORE, TRAP, LIB, EXEC, OVRINIT¨ and probably a few others. A Challenge I will offer an unspecified prize to the user who does some detective¨ work and sends me the most complete documentation on these undocumented¨ commands. A free copy of the Mex-Pack terminal emulation and remote¨ operation modules might be a fitting prize. Or perhaps a copy of the new¨ ZMATE macro text editor. I also have some recollection that someone once figured out a way to use¨ either the strings assigned to keys or the names in the phone directory as¨ string variables. So far, however, I have not been able to figure out how¨ to do it. We'll include that and any other undocumented information about¨ MEX-Plus within the framework of this challenge. Now let's begin the look at the PCP script. The PC-Pursuit Script The Purpose The purpose of this suite of MEX scripts is to make life with PC-Pursuit¨ easier. Before the recent changes in policy, using PCP was an enormously¨ taxing and frustrating experience. The outdial modems were almost always¨ busy, and it sometimes took dozens or even hundreds of tries to get¨ connected to a desired city -- each try requiring one to enter one's user ID¨ and password. Today, with the 30-hour limit on free access, things are¨ much, much better, but it is still handy to have a script take care of the¨ operation automatically. Here is basically what my script does. It calls up the local Telenet¨ access point and issues the commands to set up the proper terminal mode. ¨ Then it negotiates a connection to the city where the selected remote access¨ system (RAS) is located. If all the modems in that city are busy, the¨ script can keep trying. If all the 2400 bps modems are busy, it can even¨ automatically step down and try the 1200 bps modems. Today, one rarely¨ fails to connect on the first try at 2400, but in the past the multiple¨ tries and automatic stepdown were lifesavers. Once the connection to the city has been established, the script issues¨ the commands to put the remote modem into Racal Vadic mode and then dials¨ the number for the RAS. In Vadic mode, the modem issues call status¨ reports, so you know when the modem is dialing, when the phone is ringing,¨ when the line is busy, and when the call has simply failed. The MEX script¨ monitors these reports and responds appropriately. Once the remote system has been reached, a very short script is initiated¨ so that a maximum amount of memory will be free for MEX to use for its¨ capture and file transfer buffers. The script also programs several¨ function keys to make logging onto the RAS easier. It would be quite easy to have the PCP script chain to a script to¨ perform the complete login operation, but I generally prefer to do this¨ manually. That gives me a chance to notice if there are any new bulletins¨ or other changes in the system. Design Philosophy Two main principles guided the design of the script suite. First, as I¨ mentioned last time, I made it highly modular. This makes writing the¨ script easier and clearer but, more importantly, it overcomes memory¨ limitations. By chaining from one script to another, only one script has to¨ be in memory at one time. By making the last script a very small one,¨ almost no buffer space is lost during the time the user is working on the¨ remote system, even though a script is still in operation. The second principle is to provide as much error checking as possible. ¨ For example, at the very beginning, the script checks to make sure that the¨ local modem is connected, turned on, and responding. I learned to do this¨ after trying many times to run this and other scripts with the modem turned¨ off. In its present form, when an error is detected, the script normally¨ issues an explanatory message and then terminates. It would be better to¨ provide error recovery wherever possible. For example, having discovered¨ the PAUSE command, I might now improve the script by making it pause until¨ the user turns the modem on and presses a key. Then the script would loop¨ back and try again. There are quite a few places in the script where it will retry a failed¨ operation several times before it gives up. Sometimes PC-Pursuit just seems¨ to go out to lunch, and I have been unable to get any response from it even¨ with manually entered commands. In such cases, of course, there is nothing¨ more that the script can do. Architecture Before talking about the detailed functions of each module in the script,¨ I would like to describe the architecture. There are 6 modules, and their¨ relationships are shown in Fig. 1. --------------------------------------------------------------------------- CPM | v PCP.MEX | | v +-------------> PCPMENU.MEX <----------+ | / | \ | | / v \ | | / CPM \ | | v v | | PCPDATA.MEX PCPMAN.MEX -->+ | \ / | | \ / | | v v | | PCPCALL ------------->+ | | | | | v +----------------- PCPCONN Figure 1. This shows the architectural organization of the suite of script¨ files that comprise the complete the PCP script. ---------------------------------------------------------------------------- The central script is in the file PCPMENU.MEX. The invocation script,¨ PCP.MEX, performs some one-time operations and then transfers control to¨ PCPMENU. After that, control branches to other scripts but eventually¨ returns to the menu script. It is only from PCPMENU that the script can be¨ terminated and control returned to CP/M in a graceful fashion. The data needed to connect to a remote system can be supplied in two¨ ways. First, the menu displayed by PCPMENU lists a number of commonly¨ called systems. When one of these is selected, control branches to PCPDATA,¨ which loads the required data into MEX numerical and string variables and¨ function keys. Alternatively, there is a menu item to select if one wants to call a RAS¨ that is not on the menu. In this case, the script PCPMAN (short for¨ PCPMANUAL) provides for step-by-step, menu-driven entry of the required¨ information. If the user decides against making that call, control can be¨ returned to PCPMENU. Normally, however, control from either PCPDATA or¨ PCPMAN flows to PCPCALL. PCPCALL carries out the operations required to make PC-Pursuit connect to¨ the required city and then dial the required local telephone number. When¨ the PCP or RAS modems are busy, the script allows the user to decide whether¨ to continue trying and how many times. If the call cannot be completed and¨ the user does not want to continue trying, control returns to PCPMENU. If the remote system is reached, control is passed to the small script¨ PCPCONN (short for PCPCONNECTED). We showed this script in the previous¨ column. It puts the user into terminal mode for login. Whenever the user¨ exits back to MEX command mode, a prompt is put up. Entering the command¨ "M" returns control to PCPMENU. Other MEX commands can be entered as usual¨ for transferring files, opening capture buffers, changing STAT parameters,¨ and so on. This script suite does not make use of any subroutine scripts invoked¨ using the DO command. In all cases, control is transferred permanently to¨ another script using the READ command. There are some subroutine command¨ blocks defined by the PROC and ENDP commands. These subroutines are¨ contained within the script file because they execute faster that way and¨ because there was no reason in most cases to implement them as separate¨ files. We will now make a few comments about details of the individual script¨ files. The scripts are already heavily commented, and they should be¨ largely self-explanatory. Script PCP.MEX This script (Listing 1) initializes a number of variables. Note that¨ variables that the user is likely to want to change are placed at the¨ beginning of the script. Also note that certain values that could have been¨ hard coded into the script, such as the default number of tries to connect¨ to a city, are stored instead in numerical variables. This is like using¨ EQU parameters in assembly code and is a highly recommended practice. It is¨ not a bad maxim never to use actual numerical constants in any program;¨ always use symbolic constants. Table 1 shows how variables are used in the scripts. I'll have to¨ confess that I prepared much of this list after the fact. That was a¨ mistake. I would have made many fewer coding errors had I meticulously¨ documented the use of variables from the very beginning. In fact, the¨ comments next to each variable should be more extensive than what I show¨ here. Some of the information is incomplete; some may even be wrong. Note the way command line parameters are handled in PCP.MEX. The full¨ syntax for invocation of the script is READ PCP [menu choice] [city tries] [RAS tries] There are three optional parameters. The first is a menu choice. If you¨ know that you want to place a call to the first RAS on the menu, you can use¨ the command "READ PCP 1" to do so directly. The other two parameters are¨ the default number of times to connect to a city's outdial modem and the¨ destination modem. The parameter values are carefully validated in the script. If the¨ values are illegal, then the built-in defaults are used. Validating user¨ input is something that none of us does enough of. In the part of the script that checks the local modem, there is the¨ command WAIT STRING 2 "OK" "0" This makes the script wait for up to 2 seconds for the modem to respond with¨ either "OK" (which it will do in normal verbose mode) or "0" (which it will¨ do if it was left in terse mode). It is always a good idea to have code¨ anticipate and deal with all possible situations. I have an MNP level-4 modem, and Telenet supports MNP error correction at¨ the indial port that I use. Therefore, I put the modem into MNP mode at the¨ beginning of the PCP script and set it back to normal mode on normal exit. ¨ If you do not have an MNP modem, you will, of course, have to remove¨ (comment out) this part of the script. The script is pretty carefully written to make sure that everything is¨ proceeding correctly. After connecting to Telenet, up to two attempts are¨ made to establish the required synchronization. This same technique of¨ looping with a max-tries count in variable %z is used in many places¨ throughout the scripts. Note the use of the SLEEP command to introduce¨ delays when the system you are communicating with does not always respond¨ immediately. Script PCPMENU.MEX The menu in this script (Listing 2) is drawn inside a box and has the RAS¨ selections displayed in three columns. Free entries are filled in with a¨ row of dots. We have omitted many of the entries, including only enough to¨ show how they are generated. It is important that free entries be trapped¨ later in the script. The menu is adaptive. If one is currently connected to a city, the city¨ code and data rate are shown in the menu header, and the menu selections for¨ changing the data rate that otherwise appear at the bottom are omitted. Another example of robust coding is provided by the ABORT routine at the¨ end. Whenever this script is running, we should be connected to PC-Pursuit. ¨ Therefore, the script attempts to disconnect by sending the HANGUP command¨ that PCP likes to see. If several attempts to disconnect in this way fail,¨ however, we simply drop carrier. Script PCPDATA.MEX This script (Listing 3) is quite straightforward. It sets some default¨ key definitions that apply to many systems. Then it branches to the entry¨ for the RAS selected from the menu in PCPMENU. Here the variables necessary¨ to place the call are set and any other function key definitions are made. ¨ Then control is transferred to PCPCALL. In the listing we show the entry¨ for only one RAS. Script PCPMAN.MEX This is the second most complex module in the series (Listing 4). I used¨ to have a much simpler and less agreeable version; in honor of this column I¨ just rewrote it. It used to require manual entry of all information, and it¨ provided no checking. Now it puts up a menu of all PCP cities and allows¨ selection by number. It also keeps track of the area codes covered by each¨ city. When there is a second area code, a menu lets the user choose. The¨ script is even smart enough to include the area code as part of the local¨ number when needed and to prefix the "1" with those phone systems that¨ require it. There are two major subroutines in this module. Routine CITYNAME takes¨ the city number and produces the name of the city and state in a string¨ variable. Routine PCPCODE generates the PCP outdial code and the telephone¨ area codes for the city. The CITYNAME subroutine is also included in¨ PCPCALL. The menu of PCP cities is drawn by calling the CITYNAME routine from¨ inside a loop. This is much slower than drawing the menu directly. I put¨ the code for the CITYNAME subroutine at the beginning of the script, since I¨ think it executes a little faster from there. I wrote the script this way for two reasons. First, it illustrates some¨ interesting techniques, such as iterated loops and computed coordinates for¨ the "@" command. Second, it keeps information about the city names in one¨ place. If they are kept in more than one place, then when changes are made¨ in the future they might not be made everywhere. As it is, this danger¨ exists in several places in these scripts. For example, the menu of RASs is¨ drawn in PCPMENU, but the data for each RAS are stored in PCPDATA. When¨ changes are made, the user must be sure to keep the information¨ synchronized. Script PCPCALL.MEX Now we come to the most complex module in the script (Listing 5). This¨ one has to perform a lot of housekeeping and tricky operations. It has to¨ know if we are already connected to a city and if so which one. It then has¨ to decide how to go about connecting to the requested city. This may¨ require disconnecting from the current city and then connecting to the new¨ city. The script has to allow for things not always going right, at least¨ not the first time. If all works out, we eventually end up connected to the remote system. ¨ PCPCALL chains to PCPCONN (Listing 6), which drops one into terminal mode¨ with our function keys programmed to ease logging in. It would not be hard¨ to have the script first call a subroutine script to perform the login¨ operation automatically. The easiest way would be to store a number in a¨ numerical variable as a flag and the name of the login script file in a¨ string variable. Unfortunately, it's not clear that we have a free string¨ variable to use. One possibility would be to use the system name in¨ variable F. One could run it using the command "DO {F}". Conclusion I hope this extended example will give you a better idea of how MEX¨ script commands can be used to automate telecommunications tasks and that¨ you will come up with improvements to my script. If you do, please¨ communicate those improvements to me. * Include the following items with this article: - file PCPVAR.TCJ as Table 1 with caption: Table 1. A list showing how the string and numerical variables are used in the scripts. - file PCP.TCJ as Listing 1 with caption: Listing 1. Script PCP.MEX.. - file PCPMENU.TCJ as Listing 2 with caption: Listing 2. Script PCPMENU.MEX. - file PCPDATA.TCJ as Listing 3 with caption: Listing 3. Script PCPDATA.MEX. - file PCPMAN.TCJ as Listing 4 with caption: Listing 4. Script PCPMAN.MEX. - file PCPCALL.TCJ as Listing 5 with caption: Listing 5. Script PCPCALL.MEX. - file PCPCONN.TCJ as Listing 6 with caption: Listing 6. Script PCPCONN.MEX.