$! +-----------+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $! | *MENU.COM | VMS Menu System $! +-----------+ Public Domain Version $ GOSUB PRELIMINARIES ! Author: Harry Flowers $ VERSION = "V4.5" ! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $! This is a DCL menu system. Directions for setting up menus follow. $! A description of features for this system is to be found at the end of $! this procedure. You should use file names of the form *_MENU.COM for $! these menus. For example, CBI_MENU.COM might be a computer based $! instruction menu. The MENU is really the shell; supplied options are $! for examples only, though many of them should work on any VMS system. $!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $! Menu set-up directions: $! New with V3 is sub-menus. You can have up to 255 levels of sub-menus. $! The top (or only) level is level 0. The sub-menu levels are in the $! one to two-hundred fifty-five (1-255). The symbols for sub-menus have $! "_l" in them where "l" is the sub-menu level. Note that there is no $! change for level 0, so this menu is compatible with V2 without changing $! symbol names. If you wish that menu to display with single columns, $! start the title with the vertical bar "|" as the first character. $! $! 1) Enter the menu title(s) into MENU_TITLE(_n). $ MENU_TITLE = "|Main Menu Options" $ MENU_TITLE_1 = "Networking and Communications" $ MENU_TITLE_2 = "|File, Directory, and Disk Functions" $ MENU_TITLE_3 = "System Monitoring and Usage" $! $! 2) Enter the menu options into MENU_OPTIONS(_n) separated by "/". $! The items will appear on the menu in the order you specify. $! You may use " " (space) options for separation lines or balancing. $! Menu item headings may also be included [see (5)]. You may wish $! to use numbers for headings and letters for options to help you $! keep them straight, but there is no restriction other than it must $! be a valid character for a symbol name. $! $ MENU_OPTIONS = "N/ /F/ /S/ /P/ /X/ /L" $ MENU_OPTIONS_1 = "1/M/P/ /2/N/G/L/A/3/T/F/ /X/Z/ / " $ MENU_OPTIONS_2 = "F/ /D/ /X/Z/ " $ MENU_OPTIONS_3 = "1/M/C/ /2/U/F/ /3/S/T/ /X/Z/ " $! $! 3) Define the heading delimiter character. It must be only one character. $! It is what prints out on either side of the heading. You may wish to $! use "-", "%", "#", "=", "_", or even a space character. $ HEADING_DELIMITER = "-" $! $! 4) Enter the menu password for options which you wish to require a $! password into MENU_PASSWORD. This is for particularly dangerous $! options, and is intended to make you think twice, not for security. $ MENU_PASSWORD = "CAUTION" $! $! 5) Enter the menu option descriptions in the form "OPT_n" where "n" $! is the option. Sub-menu options must be of the form "OPT_l_n", $! where "l" is the menu level and "n" is the option. The last line $! of this section MUST be "END_MENU". Option text starting with a $! "*" will denote a heading instead of a valid option, while starting $! with a "_" will make it a "hidden" option; space will still be left $! on the menu, but the line will be blank. Hidden options are toggled $! visible with the "~" option. $! For example: $ OPT_D = "Directory listing" $! $ OPT_1 = "*File Options" $! $ OPT_N = "Networking Menu" $ OPT_1_1 = "*Electronic Mail" $ OPT_1_M = "VMS Mail" $ OPT_1_P = "Pine Mail" $ OPT_1_2 = "*Information Retrieval" $ OPT_1_N = "News" $ OPT_1_G = "Gopher" $ OPT_1_L = "Lynx (WWW)" $ OPT_1_A = "Anonymous FTP" $ OPT_1_3 = "*Connect to Other Systems" $ OPT_1_F = "File Transfer (FTP)" $ OPT_1_T = "Interactive session (Telnet)" $ OPT_1_X = "Exit the Menu" $ OPT_1_Z = "Return to Main Menu" $! $ OPT_F = "File Maintenance Menu" $ OPT_2_F = "File Management (Swing)" $ OPT_2_D = "Disks % full" $ OPT_2_X = "Exit the Menu" $ OPT_2_Z = "Return to Main Menu" $! $ OPT_S = "System Usage Menu" $ OPT_3_1 = "*Overall Usage" $ OPT_3_M = "Monitor System" $ OPT_3_C = "_Monitor Cluster" $ OPT_3_2 = "*Users" $ OPT_3_U = "Show Users" $ OPT_3_F = "Finger" $ OPT_3_3 = "*Processes" $ OPT_3_S = "Show System" $ OPT_3_T = "Top CPU usage" $ OPT_3_X = "Exit the Menu" $ OPT_3_Z = "Return to Main Menu" $! $ OPT_P = "Change password" $ OPT_X = "Exit the Menu" $ OPT_L = "Logout" $! $ END_MENU ! This line must end the menu descriptions $! $! 6) Enter the actions to be taken at these options. You must start each $! action with a label of the form "OPT_n:" where "n" is the option. $! Sub-menu options must start with a label of the form "OPT_l_n" where $! "l" is the menu level (1-255) and "n" is the option. You then place $! any lines to be executed, finished with $ END_OPT. You may wish to $! include ASK_CR to ask for a carriage return before proceeding. Before $! a particularly dangerous option, you may wish to include ASK_PASSWORD $! to ask for the menu password before proceeding. You may use MENU_EXIT $! to exit this menu. $! For example: $ OPT_P: $! $ ASK_PASSWORD ! Ask for a password $! $ PURGE/LOG [...]*.* ! Purge their files $! $ ASK_CR ! Let them see them $! $ END_OPT ! End of option $! $! Also, to have an option change menu levels (currently the only method), $! set the symbol "MENU_LEVEL" to the desired level and issue the "NEW_MENU" $! command: $ OPT_N: $! $ MENU_LEVEL = 1 ! Switch to sub-menu #1 $! $ NEW_MENU ! Go setup the new menu $! $ END_OPT ! End of option $! $ OPT_1_N: $! $ MENU_LEVEL = 0 ! Switch to main menu $! $ NEW_MENU ! Go setup the new menu $! $ END_OPT ! End of option $! $! Note that heading options need no label and actions, as they are not $! really valid options. $! $!---------------------------------------------------------------------------- $! $ OPT_N: ! "Networking Menu" $ MENU_LEVEL = 1 $ NEW_MENU $ END_OPT $! $ OPT_1_M: ! "VMS Mail" $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND $ MAIL $ END_OPT $! $ OPT_1_P: ! "Pine Mail" $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND $ PMDF PINE $ END_OPT $! $ OPT_1_N: ! "News" $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND $ NEWS $ END_OPT $! $ OPT_1_G: ! "Gopher" $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND $ GOPHER $ END_OPT $! $ OPT_1_L: ! "Lynx (WWW)" $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND $ LYNX $ END_OPT $! $ OPT_1_T: ! "Telnet" $ READ/PROMPT="Enter telnet hostname: " SYS$COMMAND HOSTNAME $ GOSUB CHK_HOSTNAME $ IF HOSTNAME .EQS. "" THEN END_OPT $ WRITE SYS$OUTPUT "" $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND $ SET VERIFY=(PROCEDURE,IMAGE) ! Show them everything $ TELNET 'HOSTNAME' $! 'F$VERIFY(0,0)' (Turns off verification, even commented out.) $ ASK_CR $ END_OPT $! $ OPT_1_F: ! "FTP" $ READ/PROMPT="Enter FTP hostname: " SYS$COMMAND HOSTNAME $ GOSUB CHK_HOSTNAME $ IF HOSTNAME .EQS. "" THEN END_OPT $ WRITE SYS$OUTPUT "" $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND $ SET VERIFY=(PROCEDURE,IMAGE) ! Show them everything $ FTP 'HOSTNAME' $! 'F$VERIFY(0,0)' (Turns off verification, even commented out.) $ ASK_CR $ END_OPT $! $ OPT_1_A: ! "Anonymous FTP" $ READ/PROMPT="Enter anonymous FTP hostname: " SYS$COMMAND HOSTNAME $ GOSUB CHK_HOSTNAME $ IF HOSTNAME .EQS. "" THEN END_OPT $ WRITE SYS$OUTPUT "" $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND $ SET VERIFY=(PROCEDURE,IMAGE) ! Show them everything $ FTP/PASS="''USERNAME'@''F$TRNLNM("MULTINET_HOST_NAME")'"- /USER="anonymous" 'HOSTNAME' $! 'F$VERIFY(0,0)' (Turns off verification, even commented out.) $ ASK_CR $ END_OPT $! $ CHK_HOSTNAME: ! Used by FTP and Telnet commands $ HOSTNAME = F$EDIT(HOSTNAME,"TRIM,COLLAPSE") $ IF HOSTNAME .EQS. "" THEN RETURN $ HOSTLEN = F$LENGTH(HOSTNAME) $ IF F$LOCATE("@",HOSTNAME) .NE. HOSTLEN $ THEN WRITE SYS$OUTPUT "@ is not a valid character in a host name" $ ERRMSG = "%NET-F-INVHOST, invalid hostname: ''HOSTNAME' " $ WRITE SYS$OUTPUT ERRMSG $ HOSTNAME = "" $ ASK_CR $ RETURN $ ENDIF $ IF F$LOCATE("'",HOSTNAME) .NE. HOSTLEN $ THEN WRITE SYS$OUTPUT "' is not a valid character in a host name" $ ERRMSG = "%NET-F-INVHOST, invalid hostname: ''HOSTNAME' " $ WRITE SYS$OUTPUT ERRMSG $ HOSTNAME = "" $ ASK_CR $ RETURN $ ENDIF $ IF F$LOCATE("&",HOSTNAME) .NE. HOSTLEN $ THEN WRITE SYS$OUTPUT "& is not a valid character in a host name" $ ERRMSG = "%NET-F-INVHOST, invalid hostname: ''HOSTNAME' " $ WRITE SYS$OUTPUT ERRMSG $ HOSTNAME = "" $ ASK_CR $ RETURN $ ENDIF $ RETURN $! $!---------------------------------------------------------------------------- $! $ OPT_F: ! "File Maintenance Menu" $ MENU_LEVEL = 2 $ NEW_MENU $ END_OPT $! $ OPT_2_F: ! "C Swing" $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND $ SWING $ END_OPT $! $ OPT_2_D: ! "Disks % full" $ DISK $ ASK_CR $ END_OPT $! $ OPT_S: ! "System Usage Menu" $ MENU_LEVEL = 3 $ NEW_MENU $ END_OPT $! $ OPT_3_M: ! "Monitor System" $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND $ MONITOR SYSTEM/END="+00:02:00" $ END_OPT $! $ OPT_3_C: ! "Monitor Cluster" $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND $ MONITOR CLUSTER/END="+00:02:00" $ END_OPT $! $ OPT_3_U: ! "Show Users" $ SHOW USERS/FULL $ ASK_CR $ END_OPT $! $ OPT_3_F: ! "Finger" $ FINGER $ ASK_CR $ END_OPT $! $ OPT_3_S: ! "Show System" $ SHOW SYSTEM $ ASK_CR $ END_OPT $! $ OPT_3_T: ! "Top CPU" $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND $ MONITOR PROCESS/TOPCPU/END="+00:02:00" $ END_OPT $! $!---------------------------------------------------------------------------- $! $ OPT_P: ! Set Password $ TYPE/NOPAGE SYS$INPUT This option is for changing your VMS password. The minimum password length is six characters. Try to choose something not easily guessed. None of the passwords will echo (you won't see the characters as you type them) for security reasons. This is what you need to do: Old Password: New Password: Verification: $ WR "" $ DEFINE/USER_MODE SYS$INPUT SYS$COMMAND $ SET PASSWORD $ ASK_CR $ END_OPT $! $ OPT_L: ! "Logout" $ LOGOUT $ END_OPT $! $ OPT_X: ! "Exit the Menu" $ OPT_1_X: $ OPT_2_X: $ OPT_3_X: $ OPT_4_X: $ MENU_EXIT $ END_OPT $! $ OPT_1_Z: ! "Return to Main Menu" $ OPT_2_Z: $ OPT_3_Z: $ OPT_4_Z: $ MENU_LEVEL = 0 $ NEW_MENU $ END_OPT $! $!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $! End of customizable menu features. Do not modify anything past this point. $! $!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $! $ CHECK_OVERRIDES: $ MYNAME = F$ELEMENT(0,";",F$ENVIRONMENT("PROCEDURE")) $ MYNAME = MYNAME - F$PARSE(MYNAME,,,"TYPE","SYNTAX_ONLY") $ LOGFILE = MYNAME + ".MENULOG" ! Logging checked here, too $ IF F$SEARCH(LOGFILE) .EQS. "" ! Only log if the file exists $ THEN LOGGING = 0 $ ELSE LOGGING = 1 $ OPT_NAME = "Menu start" $ GOSUB MAKE_LOG_ENTRY $ ENDIF $ CTRLFIL = MYNAME + ".CONTROL" ! Control file name $ IF F$SEARCH(CTRLFIL) .EQS. "" THEN GOTO SETUP_MENU $ CTRLSYM = F$PARSE(MYNAME,,,"NAME","SYNTAX_ONLY") + "_CONTROL" $ PROFILE = USERNAME ! Default profile is username $ IF F$TYPE('CTRLSYM') .NES. "" THEN PROFILE = 'CTRLSYM' ! Other profile $ TEMPFIL = "SYS$SCRATCH:MENU_" + F$GETJPI(0,"PID") + ".TMP" $ ON ERROR THEN GOTO SETUP_MENU $ DEFINE/USER_MODE SYS$OUTPUT NL: $ DEFINE/USER_MODE SYS$ERROR NL: $ SEARCH/OUTPUT='TEMPFIL' 'CTRLFIL' "!''PROFILE'!" $ IF $SEVERITY .NES. "1" $ THEN DELETE/NOLOG/NOCONFIRM 'TEMPFIL';* $ GOTO SETUP_MENU $ ENDIF $ CLOSE/NOLOG TF $ OPEN/READ TF 'TEMPFIL' $ TF_LOOP: $ READ/END=TF_END TF ALINE $ ALINE = F$EDIT(F$ELEMENT(0,"!",ALINE),"TRIM") $ IF F$EXTRACT(0,1,ALINE) .EQS. "$" THEN ALINE = ALINE - "$" $ 'ALINE' $ GOTO TF_LOOP $ TF_END: $ CLOSE/NOLOG TF $ DELETE/NOLOG/NOCONFIRM 'TEMPFIL';* $! $ SETUP_MENU: $ ON ERROR THEN GOTO ERROR_TRAP ! Reset error trap $ MENU_TEMP = F$FAO("!0UBMENU_OPTIONS!0%C!%E_''CUR_LEVEL'!%F",CUR_LEVEL) $ MENU_OPTS = F$EDIT('MENU_TEMP',"COMPRESS,UPCASE") $ MENU_TEMP = F$FAO("!0UBMENU_TITLE!0%C!%E_''CUR_LEVEL'!%F",CUR_LEVEL) $ MENU_TITL = 'MENU_TEMP' $ IF F$EXTRACT(0,1,MENU_TITL) .EQS. "|" $ THEN MENU_TITL = MENU_TITL - "|" $ MENU_DOUBLE_COLS = "FALSE" $ ELSE MENU_DOUBLE_COLS = "TRUE" $ ENDIF $ CENTER = 40 - ((F$LENGTH(MENU_TITL) + 1)/2) $ LEN_OPTIONS = F$LENGTH(MENU_OPTS) $ NUM_OPTIONS = (LEN_OPTIONS + 1) / 2 $ IF MENU_DOUBLE_COLS $ THEN NUM_LINES = (NUM_OPTIONS + 1) / 2 $ ELSE NUM_LINES = NUM_OPTIONS $ ENDIF $ TOP_SCROLL = 8 + NUM_LINES ! Top of scrolling region $ BOT_SCROLL = TT_PAGE - 1 ! Bottom of scrolling region $ IF TT_DECCRT $ THEN PROMPT_LINE = - F$FAO("!/!/") + "''ESC'[''TOP_SCROLL';''BOT_SCROLL'r" + PROMPT $ ELSE PROMPT_LINE = PROMPT $ ENDIF $! $! Check the options for descriptions. We'll have to trust that $! there is a label for the option. If there is also no label, $! the error "%DCL-W-USGOTO, target of GOTO not found" will occur. $ XOPT = 0 $ IF MENU_DOUBLE_COLS $ THEN COLUMN = 1 $ ELSE COLUMN = 25 $ ENDIF $ BASE_LINE = 8 $ SCREEN = "" $ SETUP_LOOP: $ CUR_OPT = F$ELEMENT(XOPT,"/",MENU_OPTS) $ OPT_NAME = F$FAO("!0UBOPT_!0%C!%E''CUR_LEVEL'_!%F!AS",CUR_LEVEL,CUR_OPT) $ IF CUR_OPT .EQS. " " THEN 'OPT_NAME' = "" $ IF F$TYPE('OPT_NAME') .NES. "STRING" THEN - 'OPT_NAME' = "''REVERSE'ERROR: NO DESCRIPTION FOR OPTION!''ALL_OFF'" $ OPT_DESC = 'OPT_NAME' $ IF F$EXTRACT(0,1,OPT_DESC) .EQS. "_" ! A hidden option! $ THEN IF .NOT. SHOW_HIDDEN ! Are we showing them? $ THEN OPT_DESC = "" ! Remove description $ CUR_OPT = " " ! Blank option display $ ELSE OPT_DESC = OPT_DESC - "_" ! Show hidden options $ ENDIF $ ENDIF $ IF F$EXTRACT(0,1,OPT_DESC) .EQS. "*" ! Really a heading $ THEN OPT_DESC = BOLD_ON + OPT_DESC - "*" + " " +- HEADING_DELIMITER + ALL_OFF ! Remove "*" and bold, $ CUR_OPT = HEADING_DELIMITER ! surround with delimiter $ MENU_OPTS[XOPT*2,1] := " " ! Blank out option $ ENDIF $ SCREEN = SCREEN +- F$FAO(OPTLINE,BASE_LINE+XOPT,COLUMN,CUR_OPT,OPT_DESC) $ XOPT = XOPT + 1 $ IF XOPT .GE. NUM_OPTIONS THEN GOTO DISPLAY_MENU $ IF XOPT .EQ. NUM_LINES $ THEN COLUMN = 40 $ BASE_LINE = BASE_LINE - XOPT $ ENDIF $ GOTO SETUP_LOOP $! $ DISPLAY_MENU: ! Display a Menu $! 'F$VERIFY(0,0)' (Turns off verification.) In case ^Y or ^C'd to here $ ON CONTROL_Y THEN GOTO FINISH ! Exit on ^C or ^Y $ IF P1 .NES. "" $ THEN SELECTION = P1 $ P1 = P2 $ P2 = P3 $ P3 = P4 $ P4 = P5 $ P5 = P6 $ P6 = P7 $ P7 = P8 $ P8 = "" $ GOTO GOT_SELECTION $ ENDIF $! $! Format the date as MM/DD/YY $ DATE = F$FAO("!2ZB/!2ZB/!2ZB", F$INTEGER(F$CVTIME(,,"MONTH")),- F$INTEGER(F$CVTIME(,,"DAY")),- F$INTEGER(F$EXTRACT(2,2,F$CVTIME(,,"YEAR")))) $! $! Display the top lines $ IF TT_DECCRT $ THEN WR CLEAR +- "''ESC'[1;29H''REVERSE' VMS Menu System ''VERSION' ''ALL_OFF'" $ WR SYSTEM_ID $ WR F$FAO("User: !AS ''ESC'[3;65HDate: !AS",USERNAME,DATE) $ WR "Dir : ''F$ENVIRONMENT("DEFAULT")'" $ WR "" $ WR "''ESC'[6;''CENTER'H" + BOLD_ON + MENU_TITL + ALL_OFF $ ELSE WR F$FAO("!30* ") + "VMS Menu System ''VERSION'" $ WR SYSTEM_ID $ WR F$FAO("User: !AS",USERNAME) $ WR F$FAO("Date: !AS",DATE) $ WR "Dir : ''F$ENVIRONMENT("DEFAULT")'" $ WR "" $ WR F$FAO("!''CENTER'* ") + MENU_TITL $ WR "" $ ENDIF $ WR/SYMBOL SCREEN $! $ GET_SELECTION: $! $! Format the time as HH:MM AM $ AORP = "A" $ HOUR = F$INTEGER(F$CVTIME(,,"HOUR")) $ IF HOUR .GT. 11 THEN AORP = "P" $ IF HOUR .GT. 12 THEN HOUR = HOUR - 12 $ TIME = F$FAO("!2ZB:!2ZB !ASM",HOUR,F$INTEGER(F$CVTIME(,,"MINUTE")),AORP) $! Show error message for last selection as well as the time $ IF TT_DECCRT $ THEN WR - "''ALL_OFF'''ESC'[''BOT_SCROLL';10H''ERRMSG'''ESC'[4;65HTime: ''TIME'" $ ELSE WR F$FAO("!10* ") + ERRMSG $ WR "Time: ''TIME'" $ ENDIF $! $! Get the selection $ READ/PROMPT="''PROMPT_LINE'"/TIME=180/ERROR=TIME_OUT/END=FINISH - SYS$COMMAND SELECTION $ GOT_SELECTION: $ WR ALL_OFF + RESET_SCROLL + CLEAR ! Reset screen $ TIME_OUTS = 0 ! Clear timeouts $ ERRMSG = "" ! Clear error messages $ ON CONTROL_Y THEN GOTO DISPLAY_MENU ! Come back to menu $ SELECTION = F$EDIT(SELECTION,"COMPRESS,TRIM,UPCASE") ! Clean up a bit $ ONECHR = F$EXTRACT(0,1,SELECTION) ! First character $ IF ONECHR .EQS. "" THEN GOTO NO_SELECTION ! No option present $ IF ONECHR .EQS. "$" THEN GOTO HANDLE_DCL ! Want a DCL command $ IF ONECHR .EQS. "?" THEN GOTO SHOW_HELP ! Want some help $ IF ONECHR .EQS. "~" THEN GOTO SHOW_HIDDEN_OPTS ! Show hidden options $ IF ONECHR .NES. SELECTION THEN GOSUB LOAD_P ! Maybe more than one $ IF F$LOCATE(SELECTION,MENU_OPTS) .EQ. LEN_OPTIONS THEN GOTO NOT_VALID $ OPT_NAME = F$FAO("!0UBOPT_!0%C!%E''CUR_LEVEL'_!%F!AS",CUR_LEVEL,ONECHR) $ IF LOGGING THEN GOSUB MAKE_LOG_ENTRY ! Log the option $ GOTO 'OPT_NAME' $! $ NOT_VALID: $ ERRMSG = "%MENU-W-INVALID, ''SELECTION' is not a valid option" $ P1 = "" ! If a bad selection, don't stay on autopilot $ GOTO DISPLAY_MENU $! $ TIME_OUT: $ TIME_OUTS = TIME_OUTS + 1 ! Timeouts occur at 3 minute intervals $! WR F$FAO("''ALL_OFF'''ESC'[5;65H!''TIME_OUTS'*·") ! for Debug $ IF TIME_OUTS .LT. 15 THEN GOTO GET_SELECTION ! Less than 45 minutes $ IF F$GETJPI("","PRCCNT") .GT. 0 THEN GOTO GET_SELECTION ! Subprocesses $ WR ALL_OFF + RESET_SCROLL + CLEAR ! Reset screen $ IF LOGGING $ THEN OPT_NAME = "Menu timeout" $ GOSUB MAKE_LOG_ENTRY $ ENDIF $ LOGOUT ! Since nobody's home, logout $! $ ASK_HIT_RETURN: $ WR "" $ READ/PROMPT=- "''ALL_OFF'''REVERSE'[Press RETURN to continue]''ALL_OFF'" - SYS$COMMAND DUMMY $ RETURN $! $ HANDLE_DCL: ! Issue an arbitrary DCL command for the user $ IF CAPTIVE THEN GOTO SORRY_CHARLIE $ SELECTION = SELECTION - ONECHR $ IF SELECTION .EQS. "" THEN INQUIRE SELECTION "DCL command" $ IF SELECTION .EQS. "" THEN GOTO DISPLAY_MENU $ IF SELECTION .EQS. "EX" .OR. - SELECTION .EQS. "EXI" .OR. - SELECTION .EQS. "EXIT" THEN GOTO FINISH ! Want to exit $ IF LOGGING ! Log the DCL command $ THEN OPT_NAME = " " + SELECTION $ GOSUB MAKE_LOG_ENTRY $ ENDIF $ DEFINE/USER_MODE/NOLOG SYS$INPUT SYS$COMMAND ! If they need to input $ SET VERIFY=(PROCEDURE,IMAGE) ! Show them everything $ 'SELECTION' $! 'F$VERIFY(0,0)' (Turns off verification, even commented out.) $ IF F$TRNLNM("SYS$INPUT",,,"USER",,"ACCESS_MODE") .EQS. "USER" THEN - DEASSIGN/USER_MODE SYS$INPUT ! In case they didn't run an image $ ASK_CR $ END_OPT $! $ SORRY_CHARLIE: ! A captive account has tried to issue a DCL command $ ERRMSG = "%MENU-W-CAPTIVE, Captive accounts cannot issue DCL commands" $ GOTO DISPLAY_MENU $! $ NO_SELECTION: $ ERRMSG = "%MENU-W-NOSEL, No selection entered; " +- "enter ''BOLD_ON'?''ALL_OFF' for help" $ GOTO DISPLAY_MENU $! $ SHOW_HELP: $ TYPE/PAGE SYS$INPUT This is the VMS Menu System. It is implemented entirely in Digital Command Language (DCL). To execute an arbitrary DCL command, enter "$" followed by the command. You may also just enter "$" and be prompted for your DCL command. This has the advantage of using the command recall buffer and defined keys. You may not issue arbitrary DCL commands from captive accounts. To get this help message, you enter "?". Other commands are shown as options on your menu. Just enter the letter beside the option you wish. You may exit this menu by holding the "Ctrl" key down and pressing "Z". $ IF .NOT. CAPTIVE THEN WR - " You may also exit by typing $EXIT or Ctrl C (^C)." $ WR " " $ WR " Menu command file: ''F$ENVIRONMENT("PROCEDURE")'" $ WR " Current menu level: ''CUR_LEVEL'" $ ASK_CR $ END_OPT $! $ ASK_FOR_PASSWORD: ! Ask the user for a password before proceeding $ ON CONTROL_Y THEN GOTO PASSWORD_TRAP ! Reset traps to turn terminal $ ON ERROR THEN GOTO PASSWORD_TRAP ! echo back before returning $ SET TERMINAL/NOECHO ! Don't display the password $ READ/END=PASSWORD_TRAP/PROMPT="Menu password: " SYS$COMMAND PASSWORD $ SET TERMINAL/ECHO ! Turn terminal echo back on $ ON CONTROL_Y THEN GOTO DISPLAY_MENU ! Reset traps back to their $ ON ERROR THEN GOTO ERROR_TRAP ! original destinations $ PASSWORD = F$EDIT(PASSWORD,"UPCASE,TRIM") ! Entered password $ MENU_PASSWORD = F$EDIT(MENU_PASSWORD,"UPCASE,TRIM") ! Menu password $ IF PASSWORD .EQS. MENU_PASSWORD THEN RETURN ! Valid password $ ERRMSG = "%MENU-W-INVPASS, Invalid menu password; option aborted" $ WR ERRMSG ! Go ahead and show them the error $ WAIT 00:00:03 ! Wait for them to read it here $ END_OPT ! Invalid password, return to menu $ PASSWORD_TRAP: $ SET TERMINAL/ECHO ! Turn terminal echo back on $ ON ERROR THEN GOTO ERROR_TRAP ! Reset error trap $ END_OPT ! Ctrl Y trap is reset at menu $! $ NEW_MENU: $ IF F$TYPE(MENU_LEVEL) .NES. "INTEGER" $ THEN ERRMSG = "Menu level change error" $ END_OPT $ ELSE CUR_LEVEL = 'MENU_LEVEL' $ GOTO SETUP_MENU $ ENDIF $! $ LOAD_P: $ XP = -1 $ LOAD_P_LOOP: $ XP = XP + 1 $ P'XP' = F$ELEMENT(XP," ",SELECTION) $ IF P'XP' .EQS. " " THEN P'XP' = "" $ IF (XP .LT. 8) .AND. (P'XP' .NES. "") THEN GOTO LOAD_P_LOOP $ IF P0 .NES. "" THEN SELECTION = P0 $ RETURN $! $ SHOW_HIDDEN_OPTS: $ IF SHOW_HIDDEN $ THEN SHOW_HIDDEN = "FALSE" $ ERRMSG = "[now hiding hidden options]" $ ELSE SHOW_HIDDEN = "TRUE" $ ERRMSG = "[now showing hidden options]" $ ENDIF $ GOTO SETUP_MENU $! $ PRELIMINARIES: ! This executes before almost anything else; basic setup $ SAVE_IVERIFY = F$ENVIRONMENT("VERIFY_IMAGE") ! Save & turn off $ SAVE_PVERIFY = F$VERIFY(0,0) ! verification $ SAVE_MESSAGE = F$ENVIRONMENT("MESSAGE") ! Save & turn on $ SET MESSAGE/FACILITY/SEVERITY/IDENTIFICATION/TEXT ! error messages $ CAPTIVE = F$ENVIRONMENT("CAPTIVE") ! Are we captive? $ IF F$MODE() .NES. "INTERACTIVE" THEN GOTO CLEANUP ! Only interactive $ ON ERROR THEN GOTO ERROR_TRAP ! Enable error trap $ ON CONTROL_Y THEN GOTO FINISH ! Enable ^Y and ^C trap $ ESC[0,8] = 27 ! ESC = ASCII 27 $ USERNAME = F$EDIT(F$GETJPI("","USERNAME"),"TRIM") ! Get our username $ SYSTEM_ID = F$TRNLNM("PSM$ANNOUNCE") ! Get system name $ SYSTEM_ID = F$EDIT(SYSTEM_ID,"COMPRESS,TRIM") ! Clean it up a bit $ IF SYSTEM_ID .EQS. "" ! No PSM$ANNOUNCE $ THEN VERSION = F$GETSYI("VERSION") ! Make up our own $ IF VERSION .GTS. "V6" ! MEMSIZE new in V6 $ THEN MEM = (F$GETSYI("MEMSIZE")*F$GETSYI("PAGE_SIZE"))/1048576 $ MEMORY = " (''MEM'MB)" ! Memory in MegaBytes $ ELSE MEMORY = "" ! For pre-V6 systems $ ENDIF ! $ SYSTEM_ID = "Node " + F$GETSYI("NODENAME") +- " * " + F$GETSYI("HW_NAME") + MEMORY +- " * OpenVMS " + VERSION $ ENDIF $ SYSTEM_ID = F$EDIT(SYSTEM_ID,"COMPRESS,TRIM") ! Clean it up a bit $ CENTER = 40 - ((F$LENGTH(SYSTEM_ID)+1)/2) ! Center it $ TT_PAGE = F$GETDVI("TT:","TT_PAGE") ! Page length $ PLINE = TT_PAGE - 2 ! Prompt line $ TT_DECCRT = F$GETDVI("TT:","TT_DECCRT") ! Check for DECCRT $ IF TT_DECCRT $ THEN CLEAR = ESC + "[H" + ESC + "[J" ! Clear screen $ RESET_SCROLL = ESC + "[1;''TT_PAGE'r" ! Scrolling region $ BOLD_ON = ESC + "[1m" ! Bold $ REVERSE = ESC + "[7m" ! Reverse video $ ALL_OFF = ESC + "[0m" ! All attributes off $ SYSTEM_ID = "''ESC'[2;''CENTER'H''SYSTEM_ID'" ! system name $ OPTLINE = "''ESC'[!UB;!UBH ''BOLD_ON'!AS''ALL_OFF' !AS" $ PROMPT = "''ALL_OFF'''ESC'[''PLINE';1H" +- "''BOLD_ON'Select Option:''ALL_OFF' " $ ELSE CLEAR = "" ! Clear screen $ RESET_SCROLL = "" ! Scrolling region $ BOLD_ON = "" ! Bold $ REVERSE = "" ! Reverse video $ ALL_OFF = "" ! All attributes off $ SYSTEM_ID = F$FAO("!''CENTER'* ''SYSTEM_ID'") $ OPTLINE = "!+!+ !AS !AS!/" $ PROMPT = F$FAO("!/!/Select Option: ") $ ENDIF $ TIME_OUTS = 0 ! Read timeouts $ WR = "WRITE SYS$OUTPUT" ! Shorthand write $ ERRMSG = "" ! No errors yet $ CUR_LEVEL = 0 ! Current menu level $ ASK_CR = "GOSUB ASK_HIT_RETURN" ! Wait for CR $ ASK_PASSWORD = "GOSUB ASK_FOR_PASSWORD" ! Ask for a password $ END_OPT = "GOTO DISPLAY_MENU" ! Option end, no wait $ END_MENU = "GOTO CHECK_OVERRIDES" ! Menu end $ MENU_EXIT = "GOTO FINISH" ! MENU exit $ MENU_STOP = "GOTO MENU_STOP" ! STOP replaces EXIT $ NEW_MENU = "GOTO NEW_MENU" ! For new menu level $ IF P1 .EQS. "CAPTIVE" THEN P1 = "" ! V2 compatibility $ SHOW_HIDDEN = "FALSE" ! Make hidden visible $ RETURN ! Return $! $ ERROR_TRAP: !'F$VERIFY(0,0)' (Turns off verification, even commented out.) $ ERROR = $STATUS ! Save error status $ ON ERROR THEN GOTO ERROR_TRAP ! Reset error trap $ ERRMSG = F$MESSAGE(ERROR) ! Get the message $ ASK_CR ! Let them see errors $ END_OPT ! Go to option end $! $ MAKE_LOG_ENTRY: $ OPEN/APPEND/SHARE=WRITE/ERROR=NO_LOG LOG 'LOGFILE' $! Log: yyyy-mm-dd hh:mm:ss.dd pid_____ username____ option $ WRITE/ERROR=NO_LOG LOG F$FAO("!AS !AS !12AS !AS",F$CVTIME(),- F$GETJPI(0,"PID"),USERNAME,OPT_NAME) $ CLOSE/NOLOG LOG $ RETURN $! $ NO_LOG: $ ERROR = $STATUS ! Save error status $ ERRMSG = F$ELEMENT(1,",",F$MESSAGE(ERROR)) ! Get the message $ ERRMSG = "%MENU-W-NOLOG," + ERRMSG ! Meaningful preface $! LOGGING = 0 ! If you uncomment this line no more tries will be made $ RETURN $! $ FINISH: !'F$VERIFY(0,0)' (Turns off verification, even commented out.) $ IF TT_DECCRT THEN WR ALL_OFF + CLEAR + RESET_SCROLL ! Reset screen $ IF LOGGING $ THEN OPT_NAME = "Menu exit" $ GOSUB MAKE_LOG_ENTRY $ ENDIF $ CLEANUP: $ SET MESSAGE'SAVE_MESSAGE' ! Restore messages $ EXIT 1 + 0*F$VERIFY(SAVE_PVERIFY,SAVE_IVERIFY) ! Restore verify & end $ MENU_STOP: !'F$VERIFY(0,0)' (Turns off verification, even commented out.) $ IF TT_DECCRT THEN WR ALL_OFF + CLEAR + RESET_SCROLL ! Reset screen $ SET MESSAGE'SAVE_MESSAGE' ! Restore messages $ DUMMY = F$VERIFY(SAVE_PVERIFY,SAVE_IVERIFY) ! Restore verification $ STOP ! The End $! $!------------------------ Modification History ------------------------------ $! V Date Author Description $!1.1 02/01/89 Harry Flowers Added message before exiting for $! terminals with less than VT100 $! capabilities. $!1.1 02/01/89 Harry Flowers Allowed terminal width to be changed $! after entering the MENU system. $! (Previously always reset to state when $! the MENU system was entered.) $!1.2 02/06/89 Harry Flowers Added feature for chaining from other $! captive command procedures; if CAPTIVE $! is passed in parameter one, then the $! menu will exit instead of log out. $!1.2 02/06/89 Harry Flowers Updated help, directions, and features $! sections. $!1.2 02/06/89 Harry Flowers Added trim of leading and trialing $! spaces and tabs to SYS$ANNOUNCE for $! centering properly. $!1.3 04/25/89 Harry Flowers Added identification of the command $! procedure containing this menu to the $! help screen. $!1.4 05/02/89 Harry Flowers Added ASK_PASSWORD option to ask for $! a password for a particular option. $! MENU_PASSWORD was added to parameters. $!1.4 05/03/89 Harry Flowers Fixed bug with terminal type inquiry. $!1.5 05/25/89 Harry Flowers Made changes for public domain version $! and a bug fix for the terminal width $! (lost 132 column after added inquiry). $!1.6 09/07/89 Harry Flowers Changed an INQUIRE to a READ for new $! Captive account processing in VMS 5.2 $!1.7 11/16/89 Harry Flowers Performance improvement; placed all $! screen options into a symbol to paint $! the screen faster. $!1.8 04/11/90 Harry Flowers Changed the DCL command option from a $! "@" to a "$"; seems more natural. $!1.9 06/08/90 Harry Flowers Changed header from using SYS$ANNOUNCE $! to PSM$ANNOUNCE. PSM$ANNOUNCE is more $! likely to have the site id for unsecure $! systems (networked,etc.). SYS$ANNOUNCE $! is usually something like "Unauthorized $! computer useage is illegal" nowdays. $!2.0 09/04/90 Harry Flowers Removed all of the terminal width $! handling. Removing the SET TERM's $! greatly increases the performance. $! This is V2 because some may have come $! to depend on V1.x width paranoia, and $! it no longer resets the screen. Also $! removed the SET TERM/INQUIRE; we'll $! just go with what already has been set. $!2.1 01/18/91 Harry Flowers Added " " options as separation lines $! for grouping and balancing options. $!2.2 10/09/91 Harry Flowers Added support for variable page length, $! due to a report of the problem with $! RESET_SCROLL and suggested change from $! Curtis Sardeson. $!2.3 02/06/92 Harry Flowers Added support for non-ANSI terminals $! and a way to exit out of all menus. $! Thanks to Kent Brodie for his help. $!3.0 06/11/92 Harry Flowers Added internal sub-menus. Removed $! the coding for P1 and CAPTIVE that was $! added in V1.2 because captive accounts $! are now more secure (no DCL access). $! Menu options may now be passed to the $! menu in P1 - P8 (up to 8 options). $!3.1 08/05/92 Harry Flowers Fixed problem with ever-growing prompt. $! Thanks to Jasper Rees for reporting the $! problem (it caused TKNOVF errors). $!3.2 07/28/93 Harry Flowers Added menu option headings and the $! ability to specify more than one option $! at a time at the prompt, just like you $! can since 3.0 from the command line. $!3.3 08/06/93 Harry Flowers Made option checking which was relaxed $! somewhat in 3.2 more robust. $!3.4 08/10/93 Harry Flowers Somewhere along the way, the hardcopy $! support became slightly broken (the $! prompt wouldn't show). It's fixed. $! Minor streamlining of DEC_CRT code. $!3.5 09/08/93 Harry Flowers Bug with re-display of headings when $! returning to a menu fixed. Basically, $! the "*" tag was being removed, and $! they looked like "real" options. $!4.0 07/13/94 Harry Flowers Added hidden options and ability to $! customize options and displays by $! individual user. $!4.1 07/14/94 Harry Flowers Added "~" option to view all options, $! including hidden ones, and added $! control "profiles" (see features). $!4.2 11/11/94 Harry Flowers Added single-column menu displays. $! See directions for menu titles for $! setup details (use "|" as the first $! character of the title). All menu $! titles are now centered as well. $!4.3 06/14/95 Harry Flowers If PSM$ANNOUNCE isn't defined, then $! construct a header from system info; $! don't use SYS$ANNOUNCE as a fallback. $!4.4 08/02/95 Harry Flowers Added option logging; if a file of $! the same name but extention ".MENULOG" $! exists in the same location as this $! menu file, all selections will be $! logged to that file. Make sure the $! file is writable by any users using $! this menu. The log line includes the $! time, process id, username, and option $! selected; for arbitrary DCL commands, $! followed by the command will be $! logged. $!4.5 01/08/96 Harry Flowers Fixed bug using F$PID which surfaced $! in OpenVMS V6.2. $!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $! Features: $! o One-file menu - this command file is the only one which is needed. $! It is very easy to modify the menu options for anyone with a basic $! knowledge of DCL command procedures. There is a small amount of $! error checking for consistent menu setup (for descriptions). $! o Arbitrary DCL commands - any non-captive user may issue arbitrary DCL $! commands from the command line. This can happen in one of two ways: $! 1) Precede the command by an "$", or 2) Enter an "$" and be prompted $! for the DCL command. One advantage of method #2 is that INQUIRE is $! used instead of READ, so the full command recall handling is available. $! o Automatic logout - users are logged out after 45 minutes of inactivity. $! The READ used has a 3 minute timeout. When the timeout occurs, the $! time on the menu is updated as well as the timeout counter. After 15 $! timeouts (45 minutes), the process is logged out unless it has a $! subprocess which might be active. NOTE: Broadcast messages seem to $! re-start the time for the read timeout. This extends the time a $! process waits before automatically logging out. $! o Captive account handling - captive accounts are handled specially. $! Captive accounts are not allowed to issue arbitrary DCL commands with $! the "$" on the command line. A captive account is one authorized with $! the Captive flag set in the user authorization file (with AUTHORIZE). $! It is assumed that Ctrl/Y has been disabled for captive accounts, and $! that they have not been allowed to get to a VMS prompt. Normally, $! the menu would be called directly from the account's login command $! procedure. $! o Error message display - if a fatal error occurs during the execution $! of an option, the menu waits for a carriage return allowing the user $! to see the error. It is also displayed below the input line on the $! menu screen. $! o Scrolling region for broadcast messages - while the menu is on the $! screen, the scrolling region is re-defined to be after the last line $! of options. This causes broadcast messages to scroll in this window $! and not mess up the menu display. $! o "Auto" customized - the second line of the display is whatever the $! system manager has defined for PSM$ANNOUNCE, which is used by the $! print symbiont on printouts. If PSM$ANNOUNCE is not defined, then $! a header is made up. PSM$ANNOUNCE will generally have the name of $! the installation, and in a VAXcluster environment, may have the $! system node name as well. This can easily be changed by defining a $! process logical PSM$ANNOUNCE (which will not effect the system $! definition) if you are unhappy with the contents of PSM$ANNOUNCE. $! For example: $ DEFINE PSM$ANNOUNCE "My Own Computer" $! o Option passing - up to eight (8) options can be passed to the menu on $! the command line. They will execute one after the other. Note that $! passing "CAPTIVE" as P1 is obsolete, and all parameters will be ignored. $! Multiple options seperated by spaces may also be specified once inside $! the menu as well. $! o Sub-menus - up to 256 different menu screens are possible from within $! the same menu (but not really feasible). The main menu (level 0) and $! up to 255 sub-menus may be defined. This allows multiple menus without $! having to chain to another command file. $! o Customizable - the same menu command procedure may be customized for $! individual users by replacing any of the setup items before END_MENU $! with lines in a command file in the same directory and with the same $! name but a file type of ".CONTROL". Just place the lines in the file, $! make sure it's readable, and end the lines with "!username!", where $! username is the VMS username for which you wish to override the symbol $! definitions. The leading "$" normally needed in command files is $! optional for this file, as matches will be read in and the statements $! executed within this command procedure. The most common usage of this $! is to individualize MENU_OPTIONS (and MENU_OPTIONS_*) definitions to $! restrict options available to individual users. Here's an example: $! $! MENU_OPTIONS = "N/ /F/ /P/ /X/ /L" !USER01!USER03! $! MENU_OPTIONS = "N/ /F/ /P/ /X/ /L" !USER02! $! MENU_OPTIONS_1 = "1/M/P/ /2/N/G/L/A/ /X/Z" !USER01! $! HEADING_DELIMITER = "#" !USER03! $! OPT_N = "_Networking Menu" !USER02! $! $! Users whose menu options do not include a certain option will not be $! able to execute that option. All three users would just have options $! N, F, P, X, and L in their first menu. USER01 also has his level 1 $! submenu modified. USER03 is using a different heading delimiter. $! Option "N" for USER02 is hidden on his menu (it's available, but not $! shown), though it would be better to have a MENU_OPTIONS for this $! user that moved option "N" to the end, so the spacing is better. $! Also, you may define a symbol "menu file name"_CONTROL which will $! be used instead of the user's username in the above substitutions. $! For example, if this was CBI_MENU.COM, then CBI_MENU.CONTROL would $! be the control file and CBI_MENU_CONTROL would be the symbol that $! could specify a user profile to override username.