Z-System Corner (c) by Jay Sage The Computer Journal, Issue 45 Reproduced with permission of author and publisher A Mex-Plus Script for Using PC-Pursuit 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 significant portions of the script suite 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 ways 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 put 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 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 many 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 choice for contacting 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 requested city and then dial the requested local telephone number. When either the PCP or RAS modems is 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. Because the code is quite lengthy, we are unable to print it all here. Many whole sections have been removed, and some comments have been cut out. However, there are several ways to obtain the complete scripts. First, they will probably be included on the ZSUS (Z-System Software Update Service) subscription disk that is released at about the time this issue appears. Second, the files will be posted on RASs. Finally, Art Carlson has offered to make them available to subsribers who send him a formatted, labeled diskette with return postage and mailer. 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 RAS number 1 on the menu, you can use the command "READ PCP 1" to do so directly. In case you think that it is too hard to remember the numbers, you are right; that's where ARUNZ aliases come in! My LADERA alias becomes "MEX READ PCP 1". The other two parameters are the default number of times to connect to a city's outdial modem and the destination modem, respectively. 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. I have omitted this code from the listing. If you do not have an MNP modem, you would, of course, 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 included only enough entries 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 insert the "1" prefix for 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 same CITYNAME subroutine is also included in module 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. You should particularly note the pains it takes to reset and test the PCP outdial modem and to put it into Racal-Vadic mode. If the outdial modem is busy or if the RAS is busy, the script will ask the user whether to make additional attempts and if so how many. The script is very careful to keep the user informed of exactly what is going on. If all works out, we eventually end up connected to the remote system. PCPCALL then chains to PCPCONN (Listing 6), which drops one into terminal mode with the 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 and to what extent MEX script commands can be used to automate telecommunications tasks. Please let me know if you have some ideas to improve these scripts. * 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. [This article was originally published in issue 45 of The Computer Journal, P.O. Box 12, South Plainfield, NJ 07080-0012 and is reproduced with the permission of the author and the publisher. Further reproduction for non- commercial purposes is authorized. This copyright notice must be retained. (c) Copyright 1990, 1991 Socrates Press and respective authors]