.TITLE MACRO MAILCHK (Check status of mail messages) ;======================================================================== ;= = ;= Name : Hunter Goatley = ;= Program : MAILCHK2.MAR V2.0 = ;= Language : VAX-11 MACRO-32 assembler = ;= Purpose : Show whether or not VMS mail has been read by = ;= the receiver = ;= Date : September 4, 1985 = ;= System : VAX 11/785 VAX/VMS v4.1 = ;= Shop : WKU/ACRS = ;= = ;= Suggestion : "Mail Call", Gary C. Kessler, THE DEC = ;= PROFESSIONAL, March 1985, Vol. 4, No. 3, = ;= pp. 45-48 = ;= = ;======================================================================== ;= = ;= This VAX-11 MACRO32 program shows whether or not a VMS mail = ;= message has been read by the receiver of the message. The = ;= VMS MAIL utility provides no means of determining if a = ;= message sent by a user was read by the receiver. = ;= = ;= This version must either be installed with SYSPRV privilege = ;= or executed by users with SYSPRV, since the program accesses = ;= both SYSUAF.DAT and the receiver's MAIL.MAI file. = ;= = ;= The program prompts for both the sender's name and the name = ;= of the receiver. The program checks the SYSUAF.DAT file = ;= to make sure the username of the receiver entered is a valid = ;= user; if not, a message is printed to the screen and the = ;= program prompts for a name again. If the user has a SYSUAF = ;= record, its default login device and directory are obtained = ;= and the program tries to open a MAIL.MAI file there. If the = ;= file is not there or cannot be opened, a message is printed = ;= stating that the receiver has no messages from the sender. = ;= Otherwise, the header for each MAIL message is read from = ;= the MAIL file and the sender field is checked for a match = ;= with the executing username. If there is a match, the date, = ;= subject, and status are printed. If a message is in the = ;= NEWMAIL folder, it is assumed that it has not been read; if = ;= it is in any other folder, it is assumed to have been read. = ;= The program exits on either ^Z, ^C, or at the prompt. = ;= If the program is interrupted (by ^Y), the scrolling region = ;= for the screen will still be set - always exit by one of the = ;= three methods described above. = ;= = ;======================================================================== ;= = ;= Revision history: = ;= = ;= June 16, 1986 Changed method of finding mail subject = ;= June 17, 1986 Added symbolic definitions from $UAFDEF = ;= August 3, 1986 Added ability to handle v4.x MAIL = ;= subdirectories, added $TRNLNM call to = ;= check if username given is a logical = ;= August 27, 1986 Added a few more symbols, replaced = ;= unnecessary code (MOVC3, etc.) = ;= = ;======================================================================== ;= = ;= System services used : = ;= = ;= $ASSIGN Assign an I/O channel to the terminal = ;= = ;= $EXIT Return to VMS = ;= = ;= $QIOW All terminal I/O = ;= = ;======================================================================== ;= = ;= VAX Record Management Services (RMS) used : = ;= = ;= $CLOSE Close SYSUAF and MAIL.MAI = ;= = ;= $CONNECT Associate a RAB with a file = ;= = ;= $FAB Create a Fiel Access Block for SYSUAF = ;= and the user's MAIL.MAI file = ;= = ;= $FAB_STORE Macro to store the specific MAIL.MAI = ;= file name in the FAB = ;= = ;= $GET Get records from SYSUAF and MAIL.MAI = ;= = ;= $OPEN Open SYSUAF.DAT and MAIL.MAI = ;= = ;= $RAB Create a Record Access Block for SYSUAF = ;= and MAIL.MAI = ;= = ;======================================================================== .PAGE .SUBTITLE Storage Area ; ;======================================================================== ;= = ;= D E F I N E D S T O R A G E = ;= = ;======================================================================== ; SENDER = 68 ; Offset into MAIL.MAI record of sender's name SENDER_L = 66 ; Offset into MAIL.MAI record of length of sender's name VMSMAIL_SUB_L = ^X41 ; Offset into VMSMAIL.DAT record of length of MAIL ; subdirectory specification TAB= 9 LF = 10 CR = 13 ESC= 27 MAI_K_LENGTH = 200 ; Mail record buffer is 200 bytes ; ; ;======================================================================== ;= = ;= ON_ERR macro = ;= = ;= This MACRO will check the low-order bit of R0 and branch to = ;= the address supplied if the low-order bit is clear. Useful = ;= in checking errors after system service calls. = ;= = ;= Sample call: = ;= = ;= $OPEN FAB=FILEFAB ; Open the file = ;= ON_ERR ERROR ; Error? Go handle it = ;= = ;======================================================================== ; .MACRO ON_ERR THERE,?HERE BLBS R0,HERE BRW THERE HERE: .ENDM ON_ERR ; ;================================ ;= = ;= MACRO library calls = ;= = ;================================ ; .LIBRARY /SYS$LIBRARY:LIB.MLB/ $LNMDEF ; Logical NaMe symbols $RMSDEF ; RMS symbolic definitions $RABDEF ; RAB symbols $FABDEF ; FAB symbols $UAFDEF ; User Authorization symbols $IODEF ; I/O symbols $PRVDEF ; ;*** File Access Block for SYSUAF.DAT ; SYSFAB: $FAB FNM=, - FAC=GET, - ; File Access GET only SHR= ; Allow other access to go on ; while searching ; ;*** Record Access Block for SYSUAF.DAT ; SYSRAB: $RAB FAB=SYSFAB, - ; The File Access Block RAC=KEY, - ; Record Access --- keyed KRF=0, - ; Key of Reference (position 0) KSZ=UAF$S_USERNAME, - ; Key size KBF=TESTNAME, - ; Key buffer is TESTNAME USZ=UAF$K_LENGTH, - ; Size of buffer to receive rec UBF=SYSREC ; Addr of buffer to receive rec ; SYSRAB2: ; $RAB FAB=SYSFAB, - ; The File Access Block RAC=KEY, - ; Record Access --- keyed KRF=0, - ; Key of Reference (position 0) KSZ=UAF$S_USERNAME, - ; Key size KBF=USERNAME, - ; Key buffer is TESTNAME USZ=UAF$K_LENGTH, - ; Size of buffer to receive rec UBF=SYSREC ; Addr of buffer to receive rec ; ;*** File Access Block for SYS$SYSTEM:VMSMAIL.DAT ; VMSMAILFAB: $FAB FNM=, - ; The File Name (SYSUAFC.IDX) FAC=, - ; File Access GET only SHR= ; Allow other access to go on ; while searching ; ;*** Record Access Block for SYS$SYSTEM:VMSMAIL.DAT ; VMSMAILRAB: $RAB FAB=VMSMAILFAB, - ; The File Access Block RAC=KEY, - ; Record ACcess --- keyed UBF=VMSMAILREC, - ; User BuFfer USZ=512, - ; User buffer SiZe KRF=0, - ; Key of ReFerence (position 0) KSZ=UAF$S_USERNAME-1, - ; Key size (Key is 31 bytes) KBF=TESTNAME ; Key buffer is TESTNAME ; ; VMSMAILREC: .BLKB 512 ; VMSMAIL.DAT input buffer ; ;*** File Access Block for MAIL.MAI ; MAILFAB: $FAB FAC=GET, - ; File ACcess => GET only SHR= ; Allow other access to go on ; The filename will be added at ; at run-time ; ;*** Record Access Block for MAIL.MAI ; MAILRAB: $RAB FAB=MAILFAB, - ; The File Access block RAC=SEQ, - ; Sequential organization ROP=WAT, - ; Wait until I/O is complete KRF=1, - ; The key of reference USZ=MAI_K_LENGTH, - ; The size of buffer to receive UBF=MAILREC ; The addr of buffer to receive ; JPI_LIST: ; $GETJPI item list .WORD UAF$S_USERNAME ; ... Get the username .WORD JPI$_USERNAME .ADDRESS USERNAME .LONG UN_LEN .LONG 0 ; USERNAME: ; Buffer to hold the username .BLKB UAF$S_USERNAME ; of the sender TESTNAME: ; Buffer to hold the username .BLKB UAF$S_USERNAME ; of the receiver UN_LEN: .LONG 0 ; The length of the sender name TN_LEN: .LONG 0 ; The length of receiver name TTIOSB: .BLKQ 1 ; I/O Status Buffer for TT: I/O TTNAME: .ASCID /TT/ ; The output name (terminal) TTCHAN: .LONG 0 ; I/O channel assigned to TT: NEWMAIL: .ASCII /NEWMAIL/ ; Used to check if msg read MAIL_FILE: ; The filename and extension of .ASCII /MAIL.MAI/ ; the MAIL file FILESPEC: ; Buffer for complete file spec .BLKB UAF$S_DEFDEV+UAF$S_DEFDIR+8 ; ... Make big enough for max .PAGE .SUBTITLE Screen I/O ; ;======================================================================== ;= = ;= Screen I/O ---- ANSI ESCAPE sequences, prompts, etc. = ;= = ;======================================================================== ; HEADER: .ASCII /[2J//[1;25H/"[7m VAX/VMS Mail Status Check " .ASCII /[m/ HEADER_LEN = . - HEADER PROMPT: .ASCII / Enter the user name to check ( to stop) : / .ASCII /[K/ PROMPT_LEN = . - PROMPT PROMPT2:.ASCII / Enter the user name the message is from : / .ASCII /[K/ PROMPT2_L = . - PROMPT2 HEAD2: .BYTE ^A/ /[4] .ASCII "[4mDate/Time"/[m/ .BYTE ^A/ /[12] .ASCII /[4mStatus//[m/ .BYTE ^A/ /[10] .ASCII /[4mSubject//[m/ HEAD2_LEN = . - HEAD2 NO_MSSG:.ASCII / ************ No messages ************/ NO_MSSG_LEN = . - NO_MSSG NO_USER:.ASCII / ************ No such user ************/ NO_USER_LEN = . - NO_USER NO_USER2:.ASCII /[J/ - / ************ No such user ************/ NO_USER2_LEN = . - NO_USER2 ; DATE_OFF = 4 ; Date offset into OUTBUF STAT_OFF = 25 ; Status offset into OUTBUF SUBJ_L = 38 ; Maximum SUBJECT length SUBJ_OFF = 41 ; Subject offset into OUTBUF OUTBUF: .BYTE ^A/ /[256] BLANKS: .BYTE ^A/ /[80] ; 80 blanks (clear buffers) DT: .BLKB 23 ; Spot for date/time of mssg PRMPT_LINE: ; ANSI ESC seq -> send the .ASCII /[3;1H/ ; cursor to line 3, column 1 UNDLIN: .ASCII /[4m/ ; ANSI ESC seq -> underline mode CLRATT: .ASCII /[m/ ; " " " -> turn off attr .ASCII /[K/ ; Clear to end of line CLR_END:.ASCII /[J/ ; Clear from current cursor ; position to end of display DEFSCR: .ASCII /[10;23r/ ; Define scrolling region DEFSCR_L = . - DEFSCR CLEAR: .ASCII /[1;24r//[2J/ ; Reset scrolling region & clear FROM: .ASCII /From: //[4m/ ; "From: " (with underlining) TO: .ASCII /[K//To: //[4m/ ; "To: " (W/ under) YES: .ASCII /Read / NO: .ASCII /NOT read yet / CRLF: .BYTE CR,LF ; combo ; DATE: ; Descriptor for ASCII date/time .LONG 23 ; of mail message .ADDRESS DT INBUFF: .BLKB 80 ; Input buffer for prompted info ; SYSREC: .=.+UAF$K_LENGTH ; Buffer to hold SYSUAF record MAILREC: ; Buffer to hold MAIL.MAI record .=.+MAI_K_LENGTH PRIVS: .QUAD PRV$M_SYSPRV ; TABLE_NAME: ; Logical name table to search for .ASCID /LNM$FILE_DEV/ ; ... TESTNAME equivalence string ; LOG_NAME_D: ; Logical name to translate .WORD 0 ; ... .BYTE DSC$K_DTYPE_T ; The type .BYTE DSC$K_CLASS_S ; Static .ADDRESS TESTNAME ; The name to translate LOG_NAME2_D: ; Logical name to translate .WORD 0 ; ... .BYTE DSC$K_DTYPE_T ; The type .BYTE DSC$K_CLASS_S ; Static .ADDRESS USERNAME ; The name to translate ; TRNLNM_LIST: ; Item list for $TRNLNM service .WORD UAF$S_USERNAME ; ... The maximum length of the name .WORD LNM$_STRING ; ... .ADDRESS EQUIVSTR ; .LONG EQUIVLEN ; .LONG 0 ; ... Necessary to end list ; EQUIVSTR: ; Buffer to hold SYS$PRINT equivalence .BLKB UAF$S_USERNAME ; string EQUIVLEN: ; Buffer to hold length of equivalence .LONG 0 ; string returned TRNATTR: ; $TRNLNM attributes .LONG LNM$M_CASE_BLIND ; Do not distinguish upper & lower case .PAGE .SUBTITLE MAIN Routine ; ;======================================================================== ;= = ;= M A I N R O U T I N E = ;= = ;======================================================================== ; .ENTRY MAILRRR,^M<> ; Entry point of program CLRL R10 ; Clear the YES messages flag $ASSIGN_S - ; Assign the terminal an I/O channel DEVNAM=TTNAME, - ; .... CHAN=TTCHAN ; .... ON_ERR ERROR ; Error? Die. $SETPRV_S - ; Turn on the needed privileges ENBFLG=#1, - ; .... PRVADR=PRIVS ; .... $OPEN FAB=SYSFAB ; Open SYSUAF to read TESTNAME record ON_ERR ERROR ; Die if error trying to open SYSUAF $CONNECT RAB=SYSRAB ; Connect the RAB with SYSUAF ON_ERR ERROR ; Die if error trying to connect RAB $CONNECT RAB=SYSRAB2 ; Connect the RAB with SYSUAF ON_ERR ERROR ; Die if error trying to connect RAB ; $OPEN FAB=VMSMAILFAB ; Open VMSMAIL.DAT to check for a MAIL ; ... subdirectory ON_ERR ERROR ; Error? $CONNECT RAB=VMSMAILRAB ; Connect to VMSMAIL ON_ERR ERROR ; Error? ; BSBW SET_CTRLC ; Set the ^C interrupt handler MOVAB DEFSCR,R0 ; Move addr of ANSI escape sequence to CVTBL #DEFSCR_L,R1 ; set scrolling region BSBW PUT_OUT ; Send the sequence to the terminal MOVAB HEADER,R0 ; Move the HEADER addr to R0 for PUT_OUT CVTBL #HEADER_LEN,R1 ; Move the length to R1 for PUT_OUT BSBW PUT_OUT ; Print the header ; ;******* Get the name of the sender ; ;*** NOTE: The sending USERNAME read in is not checked for its validity!!!!!! ; LOOP2: MOVC3 #UAF$S_USERNAME,BLANKS,USERNAME ; Clear USERNAME $QIOW_S CHAN=TTCHAN, - ; Prompt the user for the name to FUNC=#IO$_READPROMPT!IO$M_CVTLOW, - IOSB=TTIOSB, - ; ... of the sending user P1=INBUFF, - ; ... Put the length read in TTIOSB P2=#80, - ; ... P4=#0, - ; ... P5=#PROMPT2, - ; ... P6=#PROMPT2_L ; ... CMPW #^X1A,TTIOSB+4 ; Did user enter a ^Z? BNEQU 1$ ; No -- continue BRW BYE ; Yes -- exit the program 1$: CVTWL TTIOSB+2,R2 ; Get the length read BNEQ 5$ ; NO - continue BRW BYE ; YES - exit the program 5$: MOVL R2,UN_LEN ; Move the length of USERNAME to UN_LEN MOVC3 R2,INBUFF,USERNAME ; Move the name to USERNAME ; CMPL #UAF$S_USERNAME,UN_LEN ; Is name entered longer than max? BGEQ CHECK_FOR_USER2 ; Yes -- no such username BRW NO_SUCH_USER2 ; CHECK_FOR_USER2: $GET RAB=SYSRAB2 ; Read the TESTNAME record CMPL #RMS$_RNF,R0 ; Was record found? BNEQ 35$ BRW NO_SUCH_USER2 35$: ; ; ;***** Get the name of the MAIL recipient ; LOOP: MOVC3 #UAF$S_USERNAME,BLANKS,TESTNAME ; Clear TESTNAME $QIOW_S CHAN=TTCHAN, - ; Prompt the user for the name to FUNC=#IO$_READPROMPT!IO$M_CVTLOW, - IOSB=TTIOSB, - ; ... of the user to check P1=INBUFF, - ; ... Put the length read in TTIOSB P2=#80, - ; ... P4=#0, - ; ... P5=#PROMPT, - ; ... P6=#PROMPT_LEN ; ... CMPW #^X1A,TTIOSB+4 ; Did user enter a ^Z? BNEQU 1$ ; No -- continue BRW BYE ; Yes -- exit the program 1$: CVTWL TTIOSB+2,R2 ; Get the length read BNEQ 5$ ; NO - continue BRW BYE ; YES - exit the program 5$: MOVL R2,TN_LEN ; Move the length of TESTNAME to TN_LEN MOVC3 R2,INBUFF,TESTNAME ; Move the name to TESTNAME ; ;*** Convert the name to uppercase ; ; MOVL TN_LEN,R0 ; Get the length of the username entered ; MOVAB TESTNAME,R1 ; Move the starting address ;7$: CMPB #^A/a/,(R1) ; Is character >= "a" ; BGTR 9$ ; No - don't touch it. Yes - continue ; BICB2 #^B00100000,(R1) ; Convert each character to uppercase ; ; (turn off bit 5) ;9$: INCL R1 ; Bump up pointer into TESTNAME ; SOBGTR R0,7$ ; Finished? No - convert next ; BSBW PUT_HEADINGS ; Print the headings ; ;**** Check to see if the recipient name entered is a valid username ; CMPL #UAF$S_USERNAME,TN_LEN ; Is name entered longer than max? BGEQ CHECK_FOR_USER ; Yes -- no such username BRW NO_SUCH_USER CHECK_FOR_USER: 30$: $GET RAB=SYSRAB ; Read the TESTNAME record CMPL #RMS$_RNF,R0 ; Was record found? BNEQ 35$ BRW NO_SUCH_USER 35$: ; ;****** Get the recipient's default device and directory (home of the MAIL.MAI) ;****** and build the complete MAIL.MAI file specification ; MOVAB FILESPEC,R3 ; Address of FILESPEC buffer MOVAB SYSREC,R7 ; Address of SYSUAF record CVTBL UAF$T_DEFDEV(R7),R0 ; Get length of default device MOVC3 R0,UAF$T_DEFDEV+1(R7),(R3) ; Move the default device name ; R3 NOW points to END of def dev name CVTBL UAF$T_DEFDIR(R7),R0 ; Get length of the default directory MOVC3 R0,UAF$T_DEFDIR+1(R7),(R3) ; Move default directory name $GET RAB=VMSMAILRAB ; Read the TESTNAME record from VMSMAIL CMPL #RMS$_RNF,R0 ; Was the record found? BEQL NO_SUB ; No -- error ON_ERR ERROR ; Some other error? MOVAB VMSMAILREC+VMSMAIL_SUB_L,R0 ; Get address of length of subdirectory CVTBL (R0)+,R2 ; Get length of MAIL subdirectory BEQL NO_SUB ; If 0, no subdirectory has been set SUBL2 #2,R2 ; Don't count the brackets in length CLRL R1 ; Clear a work register MOVB (R0)+,R1 ; Get the length of the personal name ADDB2 (R0)+,R1 ; Add to it the FORWARDing addr name ADDL2 R0,R1 ; R1 now points to subdirectory INCL R1 ; Bump it past "[" or "<" in name DECL R3 ; FILESPEC ptr points to ending bracket MOVB (R3),(R3)[R2] ; Move it to the end of the subdir name MOVC3 R2,(R1),(R3) ; Move the subdirectory name INCL R3 ; Bump R3 over "]" NO_SUB: MOVQ MAIL_FILE,(R3)+ ; Add "MAIL.MAI" to FILESPEC SUBL2 #FILESPEC,R3 ; Get the length of FILESPEC ; $FAB_STORE - ; Store FILESPEC (the receiver's mail FAB=MAILFAB, - ; filename) in the FAB for MAIL FNA=FILESPEC, - FNS=R3 ; ;******* Open the recipient's MAIL file (if there), read in each mail header, ;******* to see if the file was sent by the USERNAME, and, if so, put the ;******* message status into the output buffer ; $OPEN FAB=MAILFAB ; Open the user's mail file BLBS R0,40$ ; Error opening? No messages from user BRW NO_MESS ; 40$: CMPB #FAB$C_IDX,MAILFAB+FAB$B_ORG ; Is the MAIL.MAI file indexed? BEQLU 45$ ; Yes -- v4.0 or later -- OK BRW NO_MESS ; No -- not indexed file -- print msg 45$: $CONNECT RAB=MAILRAB ; Connect RAB with MAIL.MAI BLBS R0,HERE ; Error connecting? BRW NO_MESS ; No messages from user HERE: $GET RAB=MAILRAB ; Get the first mail header CMPL #RMS$_RNF,R0 ; Was record found? BNEQ 4$ ; Yes - continue BRW NO_MESS ; No -- goto error routine 4$: CMPL #RMS$_EOF,R0 ; Was end of file found? BNEQ 5$ ; Yes - continue BRW NO_MESS ; No -- goto error routine 5$: MATCHC UN_LEN,USERNAME,MAILREC+SENDER_L,MAILREC+SENDER ; Is mail from running user? BNEQ HERE ; No -- get next record ; ;******* Here if message was from USERNAME ; $ASCTIM_S - ; Convert the date/time of the mail TIMBUF=DATE, - ; message to ASCII and put it in TIMADR=MAILREC ; the output buffer MOVC3 #17,DT,OUTBUF+DATE_OFF ; Move the date & time to OUTBUF CMPB #7,MAILREC+8 ; Is the folder name 7 bytes long? BNEQU 10$ ; No -- not folder NEWMAIL CMPC3 #7,NEWMAIL,MAILREC+9 ; Has file been read (NEWMAIL)? TSTL R0 ; Is this in NEWMAIL folder? BNEQU 10$ ; Yes - move the RECEIVED status MOVL NO,OUTBUF+STAT_OFF ; Move "Not read yet" to OUTBUF MOVL NO+4,OUTBUF+STAT_OFF+4 ; ... MOVL NO+8,OUTBUF+STAT_OFF+8 ; ... ; MOVC3 #14,NO,OUTBUF+STAT_OFF ; Move "Not read yet" to OUTBUF BRB 12$ ; Go find the subject of the message 10$: MOVL YES,OUTBUF+STAT_OFF ; Move "Read" to OUTBUF ; 12$: MOVAB MAILREC+SENDER_L,R0 ; Get the address of the Sender length CVTWL (R0),R1 ; Get the length of the sender name ADDL2 R1,R0 ; Move pointer past it ADDL2 #4,R0 ; Bump 4 more bytes to receiver length CVTWL (R0),R1 ; Get the length of the receiver name ADDL2 R1,R0 ; Move pointer past it ADDL2 #4,R0 ; Bump 4 more bytes to subject length CVTWL (R0)+,R1 ; Get the length of the subject CMPL #SUBJ_L,R1 ; Is the length > 23 characters? BLEQU 15$ ; Yes -- only move 23 BRB 20$ ; Go move it 15$: MOVL #SUBJ_L,R1 ; Here if truncate -- set length to 30 20$: MOVC3 R1,(R0),OUTBUF+SUBJ_OFF ; Move the Subj: string to OUTBUF ; MOVW #^X0D0A,(R3)+ ; Move a combo in after record MOVAB OUTBUF,R0 ; Move addr of OUTBUF for PUT_OUT SUBL3 R0,R3,R1 ; Get total length of OUTBUF data BSBW PUT_OUT ; Print the output buffer MOVC3 #80,BLANKS,OUTBUF ; Clear the output buffer MOVB #1,R10 ; Set YES messages flag BRW HERE ; Go get the next mail record ; ;******* Here if there are no messages from USERNAME ; NO_MESS: BLBS R10,STOP ; Is YES messages flag set? Yes, exit CLRL R10 ; Clear messages flag MOVAB NO_MSSG,R0 ; Move mssg addr for PUT_OUT CVTBL #NO_MSSG_LEN,R1 ; Move mssg length for PUT_OUT BSBW PUT_OUT ; Print the message ; ;******* Here when all messages in the mail file have been checked ; STOP: $CLOSE FAB=MAILFAB ; Close the MAIL.MAI file MOVC3 #30,BLANKS,TESTNAME ; Clear the TESTNAME buffer BSBW GOTO_PRMPT ; Send the cursor to the prompt line CLRL R10 ; Clear messages flag BRW LOOP2 ; Go get next username (if there is one) ; ;******* Here if TESTNAME was not found in SYSUAF ; NO_SUCH_USER: CVTLW TN_LEN,LOG_NAME_D ; Move the length of the TESTNAME to ; ... the logical name descriptor $TRNLNM_S - ; Try to translate the TESTNAME to see TABNAM=TABLE_NAME, - ; ... if it is a logical defined to be LOGNAM=LOG_NAME_D, - ; ... a username ATTR=TRNATTR, - ; ... Pay no attention to case ITMLST=TRNLNM_LIST ; ... CMPL #SS$_NOLOGNAM,R0 ; Was a match found? BEQLU 10$ ; No -- print no such user message ON_ERR ERROR ; Error? Yes -- goto ERROR MOVC5 EQUIVLEN,EQUIVSTR,#^A/ /,#UAF$S_USERNAME,TESTNAME ; Move the returned name to TESTNAME BRW CHECK_FOR_USER ; Go back up and check for the username 10$: MOVAB NO_USER,R0 ; Move mssg addr to R0 for PUT_OUT CVTBL #NO_USER_LEN,R1 ; Move the message length for PUT_OUT BSBW PUT_OUT ; Print the message BSBW GOTO_PRMPT ; Send the cursor to the prompt line BRW LOOP2 ; Go get next username ; NO_SUCH_USER2: CVTLW UN_LEN,LOG_NAME2_D ; Move the length of the TESTNAME to ; ... the logical name descriptor $TRNLNM_S - ; Try to translate the TESTNAME to see TABNAM=TABLE_NAME, - ; ... if it is a logical defined to be LOGNAM=LOG_NAME2_D, - ; ... a username ATTR=TRNATTR, - ; ... Pay no attention to case ITMLST=TRNLNM_LIST ; ... CMPL #SS$_NOLOGNAM,R0 ; Was a match found? BEQLU 10$ ; No -- print no such user message ON_ERR ERROR ; Error? Yes -- goto ERROR MOVC5 EQUIVLEN,EQUIVSTR,#^A/ /,#UAF$S_USERNAME,USERNAME ; Move the returned name to USERNAME MOVW EQUIVLEN,UN_LEN ; Move the returned length to UN_LEN BRW CHECK_FOR_USER2 ; Go back up and check for the username 10$: MOVAB NO_USER2,R0 ; Move mssg addr to R0 for PUT_OUT CVTBL #NO_USER2_LEN,R1 ; Move the message length for PUT_OUT BSBW PUT_OUT ; Print the message BSBW GOTO_PRMPT ; Send the cursor to the prompt line BRW LOOP2 ; Go get next username ; ;******* Here if , ^Z, or ^C was entered at prompt for username ; BYE: MOVAB CLEAR,R0 ; Move the ANSI escape sequence and CVTBL #11,R1 ; length to reset the scrolling BSBW PUT_OUT ; region and clear the screen $DASSGN_S - ; Deassign the I/O channel to the TT: CHAN=TTCHAN ; ... ON_ERR ERROR ; ... $CLOSE FAB=VMSMAILFAB ; Close the VMSMAIL.DAT file ON_ERR ERROR ; Error? $CLOSE FAB=SYSFAB ; Close the SYSUAF.DAT file ON_ERR ERROR ; Error? $EXIT_S ; ;******* Here if there was an error somewhere ; ERROR: PUSHL R0 ; Push message code onto stack ; CALLS #1,G^LIB$SIGNAL ; Print the error message MOVAB CLEAR,R0 ; Move the ANSI escape sequence and CVTBL #7,R1 ; length to reset the scrolling BSBW PUT_OUT ; region $EXIT_S CODE=(SP) ; Return to VMS .PAGE .SUBTITLE PUT_HEADINGS subroutine ;======================================================================== ;= = ;= Subroutine PUT_HEADINGS = ;= = ;= Functional description : = ;= = ;= This routine prints the headings "From: ", "To: ", = ;= "Date/Time", etc. = ;= = ;= Parameters : = ;= = ;= None = ;= = ;= Implicit inputs : = ;= = ;= CRLF, OUTBUF, USERNAME, UN_LEN, TESTNAME, TN_LEN, = ;= BLANKS, CLR_END = ;= = ;= Effects : = ;= = ;= None = ;= = ;======================================================================== ; PUT_HEADINGS: PUSHR #^M ; Save registers MOVAB OUTBUF,R3 ; Move addr of output buffer to R3 MOVW #^X0D0A,(R3)+ ; Move a to the output buffer MOVB #LF,(R3)+ ; Move another MOVC3 #12,FROM,(R3) ; Move "From: " and underline ESC seq MOVC3 UN_LEN,USERNAME,(R3) ; Move the username to OUTBUF MOVC3 #3,CLRATT,(R3) ; Move ESC exit underline sequence MOVC3 #14,TO,(R3) ; Move "To: " and underline sequence MOVC3 TN_LEN,TESTNAME,(R3) ; Move testname to OUTBUF MOVC3 #6,CLRATT,(R3) ; Move ESC exit underline sequence MOVW #^X0D0A,(R3)+ ; Move a to the output buffer MOVB #LF,(R3)+ ; Move another MOVC3 #HEAD2_LEN,HEAD2,(R3) ; Move the headings "From:", etc. MOVW CLR_END,(R3)+ ; Move ANSI sequence to erase to MOVB CLR_END+2,(R3)+ ; ... to end of display MOVAB OUTBUF,R0 ; Move OUTBUF addr for PUT_OUT SUBL3 R0,R3,R1 ; Move length for PUT_OUT BSBW PUT_OUT ; Print it MOVC3 #80,BLANKS,OUTBUF ; Clear the output buffer POPR #^M ; Restore registers RSB ; Return to main .PAGE .SUBTITLE GOTO_PRMPT subroutine ; ;======================================================================== ;= = ;= Subroutine GOTO_PRMPT = ;= = ;= Functional description : = ;= = ;= Send the cursor to the prompt line. = ;= = ;======================================================================== ; GOTO_PRMPT: PUSHR #^M ; Save registers MOVAB PRMPT_LINE,R0 ; Move the ANSI escape sequence and its CVTBL #6,R1 ; length that will send the cursor BSBB PUT_OUT ; Send the cursor to the command line POPR #^M ; Restore registers RSB .PAGE .SUBTITLE PUT_OUT subroutine ; ;======================================================================== ;= = ;= Subroutine PUT_OUT = ;= = ;= Functional description : = ;= = ;= Send the contents of a buffer to the terminal = ;= = ;= Parameters : = ;= = ;= Address of buffer in R0 = ;= Length of buffer in R1 = ;= = ;= Effects : = ;= = ;= None = ;= = ;======================================================================== ; PUT_OUT: PUSHR #^M ; Save the registers destroyed $QIOW_S CHAN=TTCHAN, - ; Send ASCII characters to the terminal FUNC=#IO$_WRITEVBLK, - ; ...Address in R0 P1=(R0), - ; ...Length in R1 P2=R1 POPR #^M ; Restore registers RSB .PAGE .SUBTITLE SET_CTRLC subroutine ; ;======================================================================== ;= = ;= Subroutine SET_CTRLC = ;= = ;= Functional description : = ;= = ;= This routine establishes a ^C handler. = ;= = ;= Parameters : = ;= = ;= None = ;= = ;= Effects : = ;= = ;= None = ;= = ;======================================================================== ; SET_CTRLC: ; Enable the ^C handler PUSHR #^M ; Save the registers destroyed $QIOW_S CHAN=TTCHAN, - ; Enable a ^C AST handler FUNC=#IO$_SETMODE!IO$M_CTRLCAST, - P1=C_AST ; The AST entry address POPR #^M ; Restore registers RSB ; ;======================================================================== ;= = ;= CONTROL-C handling routine --- exit the program = ;= = ;======================================================================== ; C_AST: .WORD 0 ; Entry mask -- save no regs JMP BYE ; Jump to exit the program .END MAILRRR