Documantation for EMX (Electronic Mail eXchange) v3.00 EMX will ONLY run on a Z80 based system. Program written by: Simon Ewins, Toronto, Ontario, Canada. EMX RCPM -- (416) 484-9663 ======================================================================== This is the point where much thanks, and therefore credit, is extended to the following people who were involved in Beta testing of EMX. The contributions of these people to all aspects of the final EMX system are too numerous to detail so suffice it to say that this work is much the better for their involvement. My personal thanks goes to: Harry Kaemmerer .... SYSOP - CP/M-NET East RCP/M, Piscataway, NJ, USA. Mark Howard ........ SYSOP - CNY Technical RCP/M, Syracuse, NY, USA. ======================================================================== EMX is a remote mail exchange and security control system for remote CP/M systems. The file will run quite well as a local or area network mail exchange program also, provided that some initial control program has control over one byte in memory. This document is divided into 6 main sections: 1: Overview of the system; features and advantages 2: Requirements from other sources and system hooks 3: Installation information 4: Detailed description 5: Additional notes on operation and understanding 1: EMX system overview ------------------------ EMX is small and fast! It consumes approximately 10 kilobytes of memory depending on the size of the external GETTIM file for reading the local hardware clock. EMX is self-maintaining in the sense that the users and messages file are 'mapped' such that as users and messages are deleted from the database the space is made available to the system for new users and messages. This means that the two files in question grow very slowly after a reasonable size has been established. On a system allow- ing 150 users, the users file stays at approx. 12k... the messages file will hover around 34k if a small amount of message activity takes place; with more message activity the file will obviously grow somewhat but it is unlikely that it would ever exceed 50-60k. The .COM files themselves (with all the .LBR issue utilities) total 52k on a system with a 1k allocation block size and 56k on a system with a 2k block size. The first call after midnight each day runs a short update of files such that any old users and messages are deleted. The space created is then available as mentioned above. The number of days since the last signon is used as the determining factor in the daily update of the users file. This number of days is determined from a table of attributes attached to each of 8 active user levels. Level 0 is used to indicate a deleted user, level 1 indicates a banned user. Banned users and any users with a 'days-to-deletion' value of 0 are not deleted from the database during the update routine. The exact day values and other related security in- formation for each access level are stored in a table that you set using the EMXHDR file. Level 9 is reserved for the Sysop. This system is ideal for use with a modified version of LOCK that checks a byte in high memory for a match to a preset value imbedded in the 'locked' .COM file. EMX allows such a byte-location in high memory to be specified and then places the access level of the current user into that byte. When a .COM file is run that has a value of 9 imbedded in it by PROT, then the file is for all intents and purposes non-existent if the current user is not the Sysop, with an access level of 9. An ASCII equivalent of the access level can also stored in high memory for the sake of compatability with any existing RBBS files that may need it. The MESSAGES update deletes any old messages that are to a user that just got deleted. The public messages must be deleted manually by the Sysop while in the EMXMNT routine. The access level of a user is set to 2 initially but it is auto-incremented on the next call on a new date to a level of 3.... for access greater than 3, the Sysop must manually up- grade the user by using the EMXMNT file. The auto-bump of the access level only occurs if the call is NOT on the same day as the previous call. EMXMNT stores the date and time of a user file or messages file acces in the index file and tels you what the last date/time of the last up- date was. 2: External requirements ------------------------- EMXHDR.MAC is the file that allows custom installation of EMX files.... The values of key variables in EMX are all included in EMXHDR as well as an ample amount of reserved space for future revisions. You supply ad- dresses in BYE or other area of reserved memory that EMX needs to access. Mark Howard's EMXBYE is strongly reccomended as all the needed hooks are already in place. As well, EMXHDR allows customizing the access level attributes and other definable values. A detailed description of each entry required is given in the installation section of this document. The files as tributed will NOT run as they sit without including an user created routine to read the hardware clock. The EMX-GTxx.LBR file con- tains hardware clock routines for various systems and types as available. As new ones are created they will be added to the file. Because there are so many different types of hardware clocks and systems it is impossible to write a routine to genericly handle clock data. A your own routine. The following is of importance in this regard: The labels: GETTIM TIME DATE BDATE BTIME must all be PUBLIC symbols. (use :: after the label name) On exit from the GETTIM routine the following should have occured: TIME will contain an 8 character ascii time string in the format of: hh:mm:ss the conversion to binary is done by EMX. DATE will contain an 8 character ascii date string in the format of: mm/dd/yy the conversion to binary is likewise handled by EMX. Both TIME and DATE must be terminated by a 0. BDATE and BTIME are filled in with the 3 byte binary equivalent of the ASCII time and date strings by EMX so you don't have to write a routine to handle that yourself. The addresses, however should appear in the GETTIM file. The sample .MAC file in the .LBR includes a routine to convert from BCD to ASCII. If you don't have a hardware clock a problem arises in that none of the auto-update stuff will work. EMX does not need a time to function but it does need a date. This suggestion should allow you to use EMX even without a clock although it will be more work for you to operate the system. Do NOT create a routine to allow users to enter the date when igning-on. Since record deletion depends on the date, a jerk could easily enter a date that was over a month old and thereby delete half of your users from the data-base!! The following routine is written in basic for simplicity's sake. It will allow you to change the date held in the first 3 bytes of the INDEX file each day. The routine called EMX-NCxx.MAC should be used as a GETTIM routine since it simply reads the first three bytes of the INDEX file and stores them in the DATE:: area. If you don't update the date each day then EMX-NCxx.MAC will keep returning the same date as the cur- rent day forever! The TIME string in EMX-NCxx.MAC is returned to the program as xx:xx:xx. 10 PRINT:PRINT"Date set - EMX utility program":PRINT 20 INPUT"Enter today's date (mm/dd/yy): ";d$ 30 IF D$="" THEN END ' No entry, no go 40 OPEN "r",1,"INDEX.EMX",100 ' Open file with 100 byte record length 50 FIELD #1,3 AS DD$,97 as ZZ$ ' Date is first 3 bytes 60 GET #1,1 ' Read in old index 70 A$=LEFT$(D$,2) ' Eextract month 80 B$=MID$(D$,4,2) ' Extract day 90 C$=RIGHT$(D$,2) ' Extract year 100 BD$=CHR$(VAL(A$)) ' Convert month to binary 110 BD$=BD$+CHR$(VAL(B$)) ' Add binary day to string 120 BD$=BD$+CHR$(VAl(C$)) ' And add binary year to complete string 130 LSET DD$=BD$ ' Move string to buffer 140 PUT #1,1 ' Write to first record 150 CLOSE ' Close the file 160 END ' All done EMXMNT is a file that handles the maintenance of the users and messages databases. EMXHDR allows you to set a password for use by EMXMNT ... if the password is set to nulls then the password prompt will be skipped. It is important to note that when you run EMXMNT you MUST be logged to the same drive/user as the .EMX files that are your system. The file RBBS-EMX.BAS is a sample of a .BAS file that will convert an existing RBBS user file to EMX format. If you are converting form RBBS to EMX use this as a guide for writing a basic program to do the conversions. As time goes by all RBBS type utilities will be supported by EMX. The savings in disk space and maintenance are very significant. 3: Installation ---------------- A file CMPEMX.SUB is included in the library to allow you to more easily install EMX. If your disk system is not big enough to allow all of the files to be on the same drive then you may edit CMPEMX.SUB to suit. First, create a GETTIM routine or use an existing EMX-GTxx.MAC file that matches your clock/system hardware. Second, place the GETTIM.MAC file where it can be included by M80 into the EMX.MAC and other files. NOTE: not all of the utilities for EMX require the GETTIM routines. Place the EMXSUBS.REL file where L80 can access it at link time and then M80 all the files in the .LBREr file. After you have all the resulting NOTE: Any files that do not require linking to EMXSUBS.REL will generate about 40 'Undefined Global(s)' errors from l80... this is okay. You can either ignore them or comment the EXT statements out of the EMXHDR file and use this version for inclusion with the files not linked to EMXSUBS.REL. The files included in the EMX-230.LBR file are: EMXHDR.MAC .... The installation file that will contain your system's specific required addresses and allow customization of a number of EMX factors. EMX.MAC ....... The main working file. This can be renamed to whatever you like (I call it MAIL on my system). EMXMNT.MAC .... The maintenance routines for EMX.COM. It is installed at the same time as EMX since they contain identical data areas. The maintenance routines contain full con- trol of each user's record in the users file as well as message reading and deletion. PASSCHG.MAC ... This short program allows a user to change his password while on-line. SYSOP.MAC ..... Allows a user to enter comments to a file that is read- able only by the Sysop. SYSREAD.MAC ... Allows the Sysop to read comments sent to him via SYSOP.COM. The messages can be sent to the system LST: device if desired. TOS.MAC ....... Supplies the time a user has been on the system. BYEMX.MAC ..... This is 'BYE loader'. After renaming to BYE, this file will run when an user types BYE and update the number of uploads, number of downloads, current number of nulls, current baudrate as well as printing a goodbye message. After updating the user's record it chains to your 'real' BYE the name of which is stored in the EMXHDR file. CMPEMX.SUB .... Is a SUBMIT file that will take all files and create a complete set of files for you. INDEX.EMX ..... Is the initial index file. MSGINDEX.EMX .. The initial message index file. MESSAGES.EMX .. The initial messages database. USERS.EMX ..... The initial users database. WELCOME.EMX ... An initial welcome file. SYSOP.EMX ..... The initial comments file. LASTCALR ...... Is the initial last caller file. NTXT3.LBR ..... Allows easy creation of the ENTRCPM and other .COM files using WordStar. PROTECT.LBR ... Allows you to protect and unprotect restricted .COM files. EMX-xxx.DOC ... This type of file. EMX-GT.MAC .... The GETTIM clock routine example file. RBBS-EMX.BAS .. An example of a conversion program to take an existing RBBS users file and convert it to an EMX users file. This is an actual working program that was used to convert an RBBS users file. UPD10-11.BAS .. Takes v1.0 EMX files and upgrades them to v1.1.... see section 2 for a more complete description. UPD11-2+.BAS .. Takes v1.1 EMX files and upgrades them to v2.xx ..... also see section 2 for details. SETTME.MAC .... Allows you to give a user temporary extended time-on-line. SETSYS.MAC .... Stores the current user's access level and drive/user maps and places turns the user levels/maps into Sysop's. This is handy in conjunction with standby.MAC for acces- sing the maintenance file to change a user's data while he is on line. SETUSR.MAC .... Must ONLY be used AFTER setsys. This takes the stored levels from setsys and reinstates them. STANDBY.MAC ... In conjunction with EMXBYE this suspends remote output so the online user an't see what you are doing locally. RESUME.MAC .... Reverses the actions of STANDBY and returns things to normal again. NULLS.MAC ..... Allows a user to change the number of nulls sent. EMXSUBS.REL ... This file is the file that contains all the disk I/O random file routines, print routines, and various util- ity subroutines. The file EMXSUBS.DOC is a list of the routines in EMXSUBS.REL and what each requires on entry, while running, and what it exits with. These routines may be used for either writing your own EMX routines or for adding routines to EMX itself. Now for the installation procedure. I am outlining it as a series of steps for the sakes of brevity and clarity. The procedure is quite straight-forward and should not create any difficulties..... 1: Write a GETTIM.MAC file that will read your hardware clock and return in the locations TIME and DATE two appropriate ASCII strings, null terminated. The best way to learn the rules for this one is to read either the EMX-GT.MAC file example in the .LBR or check through the EMX-GT.LBR file. 2: Edit EMXHDR as required for your system. Be very sure that the lengths of the strings required fit as indicated and that items are null padded to the right as indicated. You may want to edit some of the other .MAC files to suit you and some addresses required in them 3: Use M80 to assemble all the .MAC files in the .LBR.... then link each with L80 ... OR ... Take the files that are indicated in the CMPEMX.SUB file and place them all on the same disk and then run the submit file. If disk space prohibits this, then use the CMPEMX.SUB file as a guide to assembling linking all of the files. 4: Place the .EMX files, the LASTCALR and the new EMX and the EMXMNT .COM files in the user area specified in the EMXHDR.MAC file as the 'system' area. Also present should be BYE and your 'real' BYE ... 90% of errors that may be encountered from here on will be because a file is not in the right area and EMX can't find it. 5: Run BYE to reset the REENTR byte in high memory and then exit BYE. At this point it is well to note that a small routine to reset the re-entry byte will prove useful in that you waon't have to run BYE everytime you want to log on and check your mail... I wrote one with ZSID that does a fine job for me: #A100 #100 LD HL,REENTR ; You enter the actual hex address ; instead of 'REENTR' #103 XOR A #104 LD (HL),A #107 JP 0 ; All done #10A #^C ; Exit and save a page as NEW.COM ; or NSTRT.COM etc... 6: Run EMX.COM (or whatever you are calling it by now) and as requested enter your name, city, password. At this point it is well to note that the .COM files that are used with the EMX file are not necces- sarily in the current user area to which you are logged, (nor that a future user will be logged). EMX will take care of finding any needed .EMX files but it is up to your CCP, NZCPR, ZCMD, ZCPR, ZCPR2, ZCPR3, ZCPR33, etc. to find the initial .COM file in the system user area. 7: After you have been added to the database hit as requested and when in CP/M, log to the 'system' user area where the .EMX files are. 8: Run EMXMNT using the password selected in EMXHDR (if nulls not se- lected) and at the menu select option 1. 9: Select '4' to change the access level of your record to a 9. If desired you can also set the userarea/drive that you wish to get dropped into after signing on as well as your dive and user maps. If you are using Mark Howard's EMXBYE, you will need the maps set as it uses them for testing valid drive/user areas. 10: Select \ to quit and then option 0 to return to CP/M. 11: Run EMX and you will find that you are in a part of the signon sec- tion that you were in last time you ran EMX. This is the function of the REENTR byte that BYE must set to 0 when it first runs or when a call is finished. (See section 4) 12: At the prompt select option 2 to post a message. 13: Respond 'Y' to make the message public. 14: Enter some sort of welcome message or one that describes some system functions etc. The reason that this must be a public message and must be entered AFTER you have set your level to 9 is so that you have a 0 for days-to-deletion in your user record. This is trans- ferred to the message and therefore will ensure that there is always at least one message in the database. This is only important when you use option 4 in EMXMNT to pack the .EMX files. If pack is used on an empty file, it will do strange things... 15: After saving the message select option 0 to return to CP/M and voila, the task is done. Transfer all files to wherever they need to be and you are installed and ready to go. The RBBS-EMX file will serve as a guide to converting an RBBS user's file to an EMX user's file. 4: Detailed description ------------------------ EMX requires only one major change to BYE... An attempt was made to avoid even this one change but, unfortunately, there is no reliable way to do it besides a small mod. Actually an alternative plan would be to write a file called BYE that does the mod stuff and then chains to the real BYE... I have tried that approach and it works fine..... BYEMX.MAC is such a file that was written by Mark Howard to do the job. The change is that a byte defined as REENTR must be set to 0 each time a caller logs off, is logged off, or hangs-up, or the carrier is lost. The byte should also be set to 0 when BYE first runs. This byte is checked when EMX first runs and if it is 0 then the signon portion of the file is run and the byte is set to 1 by EMX. If the user subse- quently runs EMX while on-line the byte being 1 when checked, will bump the user to the mail/message portion of the file. The savings in disk space through this approach is in the area of 5k bytes. Other addresses that are required in high memory are maintained by EMX itself. In EMXHDR any of the following that are not being used by you should have as their addresses 0105h (LABEL JUNK::). The bytes and their names/functions are described as follows: MXUSR Usually the byte that already exists in BYE. The address of this byte is needed by EMX to set the highest accesible drive. MXDRV The byte in BYE that controls the highest accesible user area by an user. TOVAL This is optional but if available in BYE, EMX can make use of it to set the time-out in minutes for a 'sleepy' caller. The value placed here by EMX is the user's access level. NULLS Optional since at this time EMX does not use it. Future ver- sions will use this address. WRTLOC This address is filled with a 1 when EMX is writing to disk and a 0 when it is not. In BYE a lost carrier will not cause a system as long as the byte = 1. This ensures that files will be closed properly. HARDON Flag for BYE, in BYE, that sends all modem input to the system LST: device. MINON This is set by EMX to the maximum time allowed in minutes on- line for the caller. It is up to BYE to incorporate routines to check the value for an overtime limit condition and act ac- cordingly. BSPEED The baudrate indicator set by BYE when a call is received. Usually used by KMD, RDIR and RDIRL to indicate transfer times. This is optional now since EMX does not yet directly make use of this byte's address. LOCK This address is filled with the users access level in BINARY. If SYSTEM.COM files have been secured using LOCK then this byte will be checked by the locked .COM file for the value set in the .COM file at 'lock-time'. If LOCK is not being used, this ad- dress is optional. REENTR The re-entry byte for EMX that has been discussed earlier. USREC EMX stuffs the user's record number in the users file into two bytes at this address. This address MUST be provided in high memory where it cannot be overwritten by other files. This ac- tually applies to any of the above single byte stuff above. The addresses MUST all be in an area that other files do not use unless they are not being used by your system. Error #1 in EMX usually occurs because this two byte value has been altered. ASCACC This address is filled with the ascii equivalent of the user's access level. This is primarily to accomodate those converting to EMX from RBBS who have many files that look for an ASCII value. USRMAP This is a tw byte address that will contain a bit-map of the user areas that a user can access (1,2,4,5 but not 3 etc.) En- try of the userarea map (and the drive map as well) is achieved through the entry of a 16 bit binary number. A bit set to 1 means that the drive or userarea matching in position is active while a 0 indicates inactive. Bit 16 = userarea 15 and bit 0 = userarea 0. Likewise in the drive map, bit 16 = P: and bit 0 = A: - 0100000000000111 = access to userareas 0, 1, 2, 14 - 0000000100000101 = access to drives A:, C:, I: DRVMAP This 2 byte address provides mapping of drives as with userareas (A:, B:, D:, E: but not C: etc.). The USRMAP and DRVMAP func- tions will be used in conjunction with a modified GOTO, SECTION, CD type of program thus bringing much improved flexibility to system security. One could also install the routines in BYE or their CCP. MCLBUF Is the base address for the command line processor if you are running ZCPR2 or ZCMD2 with an external command buffer. The needed information to chain to another .COM file is sent here as required if the switch for this function is on. UPLOADS KMD can update this location which is initialized by EMX and if the BYE 'shadow' file in this .LBR is used then the user's re- cord will be updated accordingly.... (counts uploads to system) DNLOADS See above (UPLOADS) (counts downloads from system). LOGSTR Is the address at which the user's log-on time in 8 byte, null- terminated, ASCII format (hh:mm:ss) is stored... ideally this is set by your BYE (EMXBYE does this) or by the GETTIM routine af- ter testing the REENTR byte for a 0 as indicated earlier. TCODE Some remote systems support terminal specific strings to be sent to a user giving him reverse video etc... a one-byte code is kept in the users file to associate the user with a particular pre-defined terminal... the code is placed on signon into the address selected for BYE to use as it wishes. NOROUT Address that is checked by bye to see if a character should be sent to the modem or just the local console. WHEEL Address of the wheel byte in your system. I find the wheel byte in it's standard implemantation to be pretty useless and very limited in scope. I define this value as being the LOCK byte address and then I changed the WHLCHK routine in ZCPR2 or ZCMD2 to check for a certain level on certain functions and act ac- cordingly. This gives the wheel a crack at 9 different levels of access and can become quite powerful. The access table has 4 bytes for each access level. The first byte is the maximum drive accessible by a user (A:=1), the next is the maximum user area, next the number of minutes allowed online, and finally the number of days that the record is allowed to age before being deleted from the data-base during the automatic update (if set to 0 then no auto-delete takes place). An extension to the access table is the initial and level 3 user and drive maps these are handled seperately since they only apply to levels 2 and 3.. level 4 and higher are handled individualy with EMXMNT. Following the access table is the 'switch' area..... If the version switch is ON then the current version # is printed each time EMX is run. If the credits switch is ON then my copyright notice is printed after the version number. If the knowledge switch is ON then a question defined in EMXHDR is asked of each new user that should demonstrate an understanding on his part of the CP/M environment. (Most MS-DOS users cannot answer this question so use accordingly.) If the welcome switch is on then a file called WELCOME.EMX is typed when EMX is run provided that the REENTR byte = 0. If the special .COM switch is ON then a special .COM file is run when an user with an access level equal to or greater than 5 first enters CP/M. If the alternate file switch is ON then a file is run on exiting EMX when the signon portion was bypassed due to REENTR being non-zero. If the external command-line switch is ON then a different chaining routine is used to run the .com files selected. The next section controls some miscellaneous system functions.... The 'system' user area is the user area where your .COM files and .EMX files will reside. This user area is logged to when EMX first runs. This allows the ZCPR or ZCMD default user area to be able to work with 'secondary' files after the initial .COM file has been found. The 'system' drive is the drive that is used as the above user area is. The number of tries allowed is the number of times that a user can try to remember his name or get his password right. If it is exceeded then the file that is defined as the ERROR file is run. (Almost always BYE) The minimum access level for leaving public messages can be any number from 2 to 9.... This should help to keep random obscenities from being viewed by others, especially if you are absent when they were sent!) The maximum number of users can be based on an arbitrary decision or on the maximum size of the file you want on disk for the users database. (Each record is 100 bytes long so divide the maximum bytes wanted by 100 and that's the number to use here.) The .EMX file names should be left as they are to ensure compatability with future utilities to be released as .COM files... The .COM files in EMXHDR you CAN change with impunity. They are: First is the name of the .com file to run on normal entry to CP/M. Second, the name of a .COM file to run when it is the first time a new user has logged on. Third is the the name of the special .COM file to run if the access level is >= 5. Fourth, the name of the .COM file that runs when exiting EMX after reentering to read messages i.e., REENTR = 1 on entry to EMX. Fifth is the name of a .COM file to run in the event of a random disk error or if a user fails to log on in the specified number of tries. (Usually BYE.) The file structure for each of the files is as follows: LASTCALR. ..... 8 bytes for date (mm/dd/yy) ..... 1 byte for a comma (,) ..... 8 bytes for time (hh:mm:ss) ..... 1 byte for a comma (,) ..... x bytes for first name ..... 1 byte for a comma (,) ..... x bytes for last name ..... 1 byte for carriage return ..... 1 byte for linefeed ..... 1 byte for ^Z (end-of-file marker) INDEX.EMX ..... 3 bytes for binary date (mdy) ..... 2 bytes - next record number for message no room ..... 2 bytes - number of next message ..... 2 bytes - number of records in MSGINDEX file ..... 2 bytes - number of callers to the system ..... 2 bytes - number of system users (reaches maximum) ..... 2 bytes - number of records in users file ..... 1 byte - spare at this time ..... 1 byte - hard-copy on =1 , off =0 ..... 3 bytes - last date user file maintained ..... 3 bytes - last time user file maintained ..... 3 bytes - last date messages file maintained ..... 3 bytes - last time messages file maintained ..... 71 bytes - unused at this time USERS.EMX ..... 30 bytes - firstname lastname (0 padded) ..... 20 bytes - city/state/province (0 padded) ..... 10 bytes - password (0 padded) ..... 2 bytes - number of times on ..... 3 bytes - binary date last on (mdy) ..... 1 byte - access level ..... 1 byte - mail waiting flag (1=mail, 0=no mail) ..... 1 byte - initial drive/user (upper 4 bits=user, lower=drive) ..... 1 byte - number of nulls user needs ..... 1 byte - baudrate signed on at (read from BSPEED) ..... 2 bytes - number of uploads ..... 2 bytes - number of downloads ..... 2 bytes - userarea map ..... 2 bytes - drive map ..... 1 byte - terminal code ..... 21 bytes - unused at this time MSGINDEX.EMX ..... 30 bytes - who message is to (0 padded) ..... 2 bytes - message number ..... 3 bytes - date message left (binary mdy) ..... 1 byte - number of records (=lines) in message (64/record) ..... 2 bytes - starting record number ..... 26 bytes - message subject (0 padded) ..... 36 bytes - unused at this time MESSAGES.EMX ..... 64 bytes - one line of message (0 padded) 5: Additional Notes: -------------------- The initial welcome file is typed. This means that it is a TEXT file called WELCOME.EMX not a .COM file like the ones that used on exiting EMX. To pack messages with the EMXMNT program you MUST have at least one message in the data-base ... (you can't pack nothing!) ------------------------------------------------------------------------ I realize that I am not very good at writing documentation but this is free and I'm not about to hire a technical writer! I am, however, quite good at talking on the phone! If you are having any difficulty with EMX get in touch with me and I will do whatever I can to help you. The best way to get in touch with me is at my RCPM in Toronto at (416) 484-9663. Through messages left there, we can arrange for a transfer of files that are giving you trouble or for a voice contact.... Because of strange things that have happened in the past I prefer not to list my voice num- ber here but will give it to you through my RCPM. Best of luck and PLEASE let me know of any bugs although the testing of this program has been lengthy and extensive, anything can slip through, I guess!! Simon Ewins, 07/04/84 - end -