Trailing-Edge
-
PDP-10 Archives
-
BB-KL11L-BM_1990
-
t20src/lisvax.mac
There are 26 other files named lisvax.mac in the archive. Click here to see a list.
; COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1985, 1989.
; ALL RIGHTS RESERVED.
;
; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
; ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE
; INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER
; COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
; OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY
; TRANSFERRED.
;
; THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
; AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
; CORPORATION.
;
; DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
; SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
TITLE LISVAX
TWOSEG
RELOC 400000
SEARCH MACSYM,MSUNV
EXTERN DB%VD8,MX%UNQ,MX$VAL,MXERRS,SCAN%P,UF%CLO,UF%OPE,UF%WRI,UM%GET
EXTERN UM%REL,UMP%GE,UMP%RE,UN%ABO,UN%ACC,UN%CLO,UN%OPE,UN%REA,UN%STA
EXTERN UN%WRI,US%SLE,RELASC,LOG,NODNAM,NMLDIE,ELOG
EXTERN NW$RCF
IFNDEF T20SYS,<T20SYS==0> ;***NOTE*** TOPS-10 by default!
;To build the TOPS-20 version, create T20.MAC which contains 1 line:
;T20SYS==-1. Then COMPILE T20+LISVAX.
DEFINE TOPS10 <IFE T20SYS,>
DEFINE TOPS20 <IFN T20SYS,>
DEFINE $TRACE(S) <
REPEAT 0,<
PUSH P,T1
PUSH P,T2
PUSH P,T3
PUSH P,T4
PUSH P,T5
MOVEI T1,[ASCIZ /S/]
PUSH P,T1
PUSH P,[0] ;[318]
CALL LOG
ADJSP P,-2
POP P,T5
POP P,T4
POP P,T3
POP P,T2
POP P,T1
>>
;AC Definitions
TF==0 ;SCRATCH REGISTERS
T1==1
T2==2
T3==3
T4==4
T5==5
T6==6
T7==7
T10==10
BUFPTR==11 ;Pointer to mail file header
WRDCNT==12 ;Number of words in the message
MSGPTR==13 ;Pointer into message being built
VARPTR==14 ;Points to variables and pointers buffer
;Ac 15 reserved for bliss
P==17 ;Stack
FLGWRD==0 ;Flag word for protocol options
USRNOT==1B0 ;Notify receiving user
USRBLK==1B1 ;Send the message in blocks
USRPRE==1B2 ;Master prefixes sender's node
USRCC==1B3 ;There WILL BE A CC LIST
SNQTS==1B4 ;Sender Needs QuoTeS
UTLPTR==1 ;Reusable pointer
LSTYP==2 ;To:/cc: list being processed
MSGNUM==3 ;Number of pages in the message
NOMORE==4 ;Any more destination strings or not
MSGRCT==5 ;Number of records in the message
IDNUM==6 ;Packet id
LSTADR==7 ;Last entry in the current address list
NXLST==10 ;Last address reached in previous page
NXUSR==11 ;If more than one page, points to the
;First destination string
MSGSTR==12 ;Address of beginning of the message
SCRAT1==13 ;Scratch space
SCRAT2==14
SCRAT3==15
SCRAT4==16
MAIPTR==17 ;Pointer to mail file spec
FAINDE==20 ;Pointer to unknown node error message
VALUSR==21 ;Pointer for use with mx$val routine
SUCMSGF==22 ;Success message for user validation
FAIMSG==23 ;Failure message for user validation
NODENM==24 ;Points to local node name
BYTNUM==25 ;Number of bytes in failure message
LOCAL==26 ;Local node found flag
NODE7==27 ;Points to local node name
NAMLIN==30 ;Number of names/line in the to: list
STABUF==31 ;Points to start of buffer
BUFBYT==32 ;Number of bytes in the buffer
EOFMES==33 ;End of the vax message has been found
NUMUSR==34 ;Number of recipients
CNNBLK==35 ;Connect block address
SNDSTR==36 ;From string pointer
NODSTR==37 ;Node name pointer (7 bit bytes)
USRSTR==40 ;User name pointer
ADRSPA==41 ;Pointer to recipient list
WRKBUF==42 ;Working buffer address
WRKBU2==43 ;Second working buffer address
FILNB==44 ;File number of mail file
DATLNK==45 ;Lisvax's data link
NODCNT==46 ;Number of node names in recipient string
LNKCLO==47 ;Link closed due to invalid user
FAIMG2==50 ;Second part of user error text
NODMSG==51 ;Pointer to node name error text
STABLK==52 ;Address of first recipient status block
STAPTR==53 ;Address of current recipient status entry
FILCLO==54 ;Mail file closed
INVPTR==55 ;Address of current recipient status block
NUMVAR==56 ;Size of variable address list
VERSNM==3 ;Version number of protocol
VAXTYP==7
VAXOBJ==^D27 ;Vax object type
MINSIZ==^D12 ;Minimum size for version 3 protocol
TOPS20== ;Operating system type
OPRESW==4 ;Number of words for slave optional data
OPRESB==12 ;Number of bytes for slave optional data
LSTREC==^D897 ;Used to determine if room for another record
D2==2 ;Block sizes
BY2WRD==5 ;Number of 7 bit bytes in a word
NUMTRY==6 ;Times to check for closed link
SLPTIM==20 ;Time to sleep between link status check
D68==^D68
D70==^D70
CBKSIZ==^D64 ;Connection block size
PROVER==377B7 ;Protocol version field
OSTYPE==377B31 ;Operating system type
MSTSND==1B0 ;Master wishes to send message in blocks
SLVSND==1B1 ;Slave willing to receive message in blocks
MSTPRE==1B2 ;Master wishes to prefix node name to send name
SLVPRE==1B3 ;Slave willing to accept node name prefixed
MSTCC==1B4 ;Master wishes to send a cc: list
SLVCC==1B5 ;Slave willing to accept a cc: list
SUCBIT==1B25 ;Success bit
FAIBIT==1B24 ;Failure bit
ST%CLO==1B33 ;Link was closed
ST%ABT==1B32 ;Link was aborted
INVLND==1B35 ;Invalid node in recipient string
INVLUS==1B34 ;Invalid recipient name
QUOTE==42 ;Ascii value of quote character
MAXSND==^D100 ;Maximum number of recipients
MAXNUM==774 ;Maximum size of error block
OPDEF PJRST [JUMPA 17,]
.DECNT==1 ;Decnet listener's id
TOPS10< .DCX11=13>
TOPS10< IP.JAC==1B0>
TOPS10< EXTERN GETDAT>
TOPS20< SEARCH MONSYM>
SALL
;All routines use ACs 11-14 as Global registers. These have the symbols
;BUFPTR, WRDCNT, MSGPTR, and VARPTR.
;Allocate buffer spaces
LISVAX::$TRACE <At LISVAX...>
CALL GETBUF ;(/)
;Set up the error messages
CALL SETMSG ;(/)
;Determine the protocol version being used and make the connection
LISNXT: $TRACE <At LISNXT...>
CALL CONECT ;(/)
;Create and open the unique name mail file.
CALL MAIOPN ;(/)Open the mail file
IFNSK.
$TRACE <Error opening the mail file>
CALL FORDIS ;(/)An error occurred, abort the connection
CALL CLSFIL ;(/)Release the message file
CALL RELMAI ;(/)Release space for the mail file spec
JRST LISNXT ;Try again
ENDIF.
;Build the sender record
CALL SNDREC ;(/)Build the sender record
IFNSK.
$TRACE <Error building the sender record>
CALL FORDIS ;(/)An error occurred, abort the connection
CALL CLSFIL ;(/)Release the message file
CALL RELMAI ;(/)Release space for the mail file spec
JRST LISNXT ;Try again
ENDIF.
;Build the date and from fields for the mail file
CALL MFHEAD ;(/)Build first part of the mail file header
;Complete and send the mail message
CALL DSTREC ;(/)Finish the message and send to mx
IFNSK.
$TRACE <Error return from DSTREC>
CALL FORDIS ;(/)No, force a disconnect
SKIPN FILCLO(VARPTR) ;Skip if message file is already closed
CALL CLSFIL ;(/)Release the message file
CALL RELMAI ;(/)Release space for the mail file spec
CALL RLSEPG ;(/)Release any error block pages
JRST LISNXT ;Wait for the next vax call
ENDIF.
;Disconnect
CALL DISCON ;(/)Wait for the disconnect
CALL RELMAI ;(/)Release space for the mail file spec
JRST LISNXT ;Go for the next connection
SUBTTL GETBUF GET BUFFERS
;Get space for list of addresses and pointers
GETBUF: $TRACE <At GETBUF...>
PUSH P,[NUMVAR] ;Get space for the address list
CALL UM%GET ;(1S/T1)Do it
ADJSP P,-1 ;Reset the stack
JUMPLE T1,BUFERR ;An error occurred
MOVE VARPTR,T1 ;Save the address of the list
;Get space for the connect block
PUSH P,[CBKSIZ] ;Size of the connection block
CALL UM%GET ;(1S/T1)Get the space
ADJSP P,-1 ;Adjust the pointer
JUMPLE T1,BUFERR ;Error, halt
MOVEM T1,CNNBLK(VARPTR) ;Save the address for later
;Allocate space for use with mx$val
PUSH P,[^D60] ;The amount of words
CALL UM%GET ;(1S/T1)Get them
ADJSP P,-1 ;Reset the stack
JUMPLE T1,BUFERR ;An error occurred
HRLI T1,[POINT 7] ;Make into a pointer
MOVEM T1,VALUSR(VARPTR) ;Save for later
;Allocate a page for message to mx
CALL UMP%GET ;(/T1)Get a page
JUMPL T1,BUFERR ;An error occurred, halt
LSH T1,^D9 ;Change page number to an address
MOVEM T1,MSGSTR(VARPTR) ;Address of start of the message
;Allocate a page for invalid recipients
CALL UMP%GET ;(/T1)Get a page
JUMPL T1,BUFERR ;An error occurred, halt
LSH T1,^D9 ;Change page number to an address
MOVEM T1,STABLK(VARPTR) ;Address of start of invalid recipient buffer
;Get space for building the mail file header (date, from, to, mailed to fields)
CALL UMP%GET ;(/T1)Get a page
JUMPL T1,BUFERR ;An error occurred, halt
LSH T1,^D9 ;Change page number to an address
MOVE BUFPTR,T1 ;Make into
HRLI BUFPTR,(POINT 7) ;A pointer
MOVEM BUFPTR,STABUF(VARPTR) ;Save start for write to mail file
;Allocate space for the from string
PUSH P,[D70] ;Amount of space needed
CALL UM%GET ;(1S/T1)Get the space
ADJSP P,-1 ;Reset the stack
JUMPLE T1,BUFERR ;An error occurred
HRLI T1,(POINT 8) ;Make a pointer
MOVEM T1,SNDSTR(VARPTR) ;Save for later
;Allocate space for the node name and user name
PUSH P,[D2] ;Two words for the node name
CALL UM%GET ;(1S/T1)Get them
ADJSP P,-1 ;Reset the stack
JUMPLE T1,BUFERR ;An error occurred
HRLI T1,(POINT 7) ;Make it into a pointer
MOVEM T1,NODSTR(VARPTR) ;Save for later
PUSH P,[D68] ;Space for the user name
CALL UM%GET ;(1S/T1)Get them
ADJSP P,-1 ;Reset the stack
JUMPLE T1,BUFERR ;An error occurred, halt
HRLI T1,(POINT 7) ;Make it into a pointer
MOVEM T1,USRSTR(VARPTR) ;Save for later
;Allocate space for the recipient buffer
PUSH P,[^D100] ;Get room for the recipient
CALL UM%GET ;(1S/T1)Do it
ADJSP P,-1 ;Reset the stack pointer
JUMPLE T1,BUFERR ;Error, halt
HRLI T1,(POINT 8) ;Make it into a pointer
MOVEM T1,ADRSPA(VARPTR) ;Save for later
;Allocate space for a working buffer
PUSH P,[^D100] ;The number of words to get
CALL UM%GET ;(1S/T1)Get them
ADJSP P,-1 ;Reset the stack
JUMPLE T1,BUFERR ;An error occurred, halt
MOVEM T1,WRKBUF(VARPTR) ;Save for later
;Allocate space for a second working buffer
PUSH P,[^D100] ;The number of words to get
CALL UM%GET ;(1S/T1)Get them
ADJSP P,-1 ;Reset the stack
JUMPLE T1,BUFERR ;An error occurred, halt
MOVEM T1,WRKBU2(VARPTR) ;Save for later
RET ;Return
BUFERR: PUSH P,[POINT 7,[ASCIZ /No memory available at BUFERR:(LISVAX)/]]
PUSHJ P,NMLDIE ;No memory available, halt
SUBTTL SETMSG - SET UP THE ERROR MESSAGES
;Set up the success/fail messages
SETMSG: $TRACE <At SETMSG...>
SETZ T2, ;Zero flag word
TLO T2,SUCBIT ;Set the success bit
MOVEM T2,SUCMSG(VARPTR) ;Save for later
SETZ T2, ;Zero the flag word
TLO T2,FAIBIT ;Set the failure bit
MOVEM T2,FAIMSG(VARPTR) ;Save for later
MOVEI T1,ERMSG3 ;Address of invalid node name text
HRLI T1,(POINT 8) ;Make into a pointer
MOVEM T1,NODMSG(VARPTR) ;Save for later
;Make a pointer to the local node name to be used in error messages and for
;To: list processing
MOVEI T4,NODNAM ;Address of the local node name asciz string
HRLI T4,(POINT 7) ;Make into a pointer
MOVEM T4,NODE7(VARPTR) ;Save for later
RET
ERMSG1: BYTE(8)"%","N","e","t","w","o","r","k"," ","M","a","i","l"," ","E","r"
BYTE(8)"r","o","r",":"," ","N","o"," ","s","u","c","h"," ","U","s","e"
BYTE(8)"r"," ","A","t"," ","N","o","d","e"," "
ERMSG3: BYTE(8)"%","N","e","t","w","o","r","k"," ","M","a","i","l"," ","E","r"
BYTE(8)"r","o","r"," ","N","o"," ","S","u","c","h"," ","N","o","d","e"
BYTE(8)" "
SUBTTL CONECT DETERMINE THE PROTOCOL AND MAKE THE CONNECTION
;Fill in the connect block
CONECT: MOVE T1,CNNBLK(VARPTR) ;Get address of the data block
SETZM 0(T1) ;Zero the first word
HRLI T2,0(T1) ;Source word
HRRI T2,1(T1) ;Destination word
BLT T2,CBKSIZ-1(T1) ;Zero the rest of the block
MOVX T2,VAXOBJ ;Get the object type
MOVEM T2,2(T1) ;And store it
PUSH P,[1] ;Connect type 1, target
PUSH P,T1 ;Address of the connection block
PUSH P,[0] ;Required by un%ope
PUSH P,[0] ;Required by un%ope
PUSH P,[0] ;Required by un%ope
CALL UN%OPEN ;(5S/T1)Open and block for initiation
ADJSP P,-5 ;Reset the stack
SKIPLE T1 ;Obtained a data link number?
IFSKP.
PUSH P,[^D300] ;Error, sleep for awhile
CALL US%SLE ;(1S/T1)
ADJSP P,-1 ;Reset the stack
JRST CONECT
ENDIF. ;Try again
MOVEM T1,DATLNK(VARPTR) ;Save the data link number
MOVE T1,[NW$RCF] ;Log a "received connection from" msg
MOVEI T2,3 ;Skip over node number and byte count
ADJBP T2,@CNNBLK(VARPTR) ;Get the pointer to the node name
CALL SMXERR ;(T1,T2)Tell mx
;Set up to accept the connection
SETZM FLGWRD(VARPTR) ;Assume version "0.0"
JRST VERO ;For now, version "0.0"
REPEAT 0,< MOVE T4,-1(P) ;Any optional data sent
JUMPE T4,VER0 ;No, so version "0.0"
HRRZ T5,-2(P) ;Get the address of the data
LOAD T2,PROVER,0(T5) ;Get the version number
CAIE T2,VERSNM ;Is it the expected protocol version
JRST VER0 ;No, so assume version "0.0"
LOAD T2,OSTYPE,0(T5) ;Get the type of operating system
CAIN T2,VAXTYP ;From a vax
CAIGE T4,MINSIZ ;Are protocol bytes present?
JRST VER0 ;No, so assume version "0.0"
;Protocol version 3.0 being used, check the options
PUSH P,[OPRESW] ;Allocate space response optional data
CALL UM%GET ;(1S/T1)Do it
ADJSP P,-1 ;Adjust the stack
JUMPLE T1,R ;An error occurred
MOVEM T1,SCRAT1(VARPTR) ;Save for the buffer release
SETZM 0(T1) ;Zero the first word
SETZM 1(T1) ;And the next
MOVEI T2,VERSNM ;Get our protocol version
STOR T2,PROVER,0(T1) ;And store it
MOVEI T2,TOPS20 ;Get our operating system type
STOR T2,OSTYPE,0(T1) ;And store it
SETZM T2 ;Prepare for flag word
MOVE T3,1(T5) ;Get the master options word
TXNE T3,USRNOT ;User to be notified?
TXO T2,USRNOT ;Yes, set the flag bit
MOVE T3,2(T5) ;Get the master mode word
SETZM T4 ;Prepare for the slave mode word
TXNE T3,MSTPRE ;Master to prefix node to sender name
TXO T4,SLVPRE ;Yes, set the slave mode word
TXNE T3,MSTPRE ;Master to prefix node to sender name
TXO T2,USRPRE ;Yes, set the flag bit
TXNE T3,MSTCC ;Master to send a cc: list
TXO T4,SLVCC ;Yes, set the slave mode word
TXNE T3,MSTCC ;Master to send a cc: list
TXO T2,USRCC ;Yes, set the flag bit
MOVEM T4,2(T1) ;Store in slave mode word
MOVEM T2,FLGWRD(VARPTR) ;Store in the flag word
;Accept the connection
PUSH P,DATLNK(VARPTR) ;The data link identifier
PUSH P,[OPRESW] ;Number of bytes
HRLI T1,(POINT 8) ;Make it a pointer to the optional data
PUSH P,T1 ;Place on the stack
CALL UN%ACC ;(3S/T1)Accept the connection
ADJSP P,-3 ;Reset the stack
HRRZ T1,SCRAT1(VARPTR) ;Address of buffer to be released
PUSH P,T1 ;Pass as an argument
PUSH P,[OPRESW] ;Number of words to be released
CALL UM%REL ;(2S/T1)Release the buffer
ADJSP P,-2 ;Reset the stack
TRNN T1,1 ;An error occurred?
RET ;Yes
RETSKP > ;No
;Using version "0.0"
VERO: $TRACE <At VERO...>
PUSH P,DATLNK(VARPTR) ;Data link number
PUSH P,[0] ;No optional data
PUSH P,[0] ;No optional data
CALL UN%ACC ;(3S/T1)Accept the connection
ADJSP P,-3 ;Restore the stack
TRNN T1,1 ;O.k.?
SKIPA ;No, try again
RET ;Yes
PUSH P,[^D60] ;An error, sleep for awhile
CALL US%SLE ;(1S/T1)
ADJSP P,-1 ;Reset the stack
JRST VERO ;Try again
SUBTTL MAIOPN GET THE MAIL FILE NAME AND OPEN THE MAIL FILE
;Get the mail file name
MAIOPN: $TRACE <At MAIOPN...>
CALL MX%UNQ ;(/T1)Get the file spec
HRLI T1,(POINT 7) ;Make into a pointer
MOVEM T1,MAIPTR(VARPTR) ;Save for later
;Open the mail file
PUSH P,T1 ;Pointer to file spec
PUSH P,[2] ;Write access
PUSH P,[0] ;No error buffer
CALL UF%OPE ;(3S/T1)Open the mail file
ADJSP P,-3 ;Restore the stack
JUMPLE T1,R ;An error occurred
MOVEM T1,FILNB(VARPTR) ;Save the file number for later
RETSKP ;And return true
SUBTTL SNDREC - CREATE THE SENDER RECORD
SNDREC: $TRACE <At SNDREC...>
MOVE MSGPTR,MSGSTR(VARPTR) ;Address of start of message
SETZM MSGRCT(VARPTR) ;No records yet
ADDI MSGPTR,.HDRSZ ;Skip the header record for now
AOS T4,MSGRCT(VARPTR) ;Increment the number of records
MOVEM T4,.RECNM(MSGPTR) ;Store it
MOVEI T4,.SENDR ;Get the record type
MOVEM T4,.RECTY(MSGPTR) ;Store it
MOVEI WRDCNT,.HDRSZ ;Number of words = record header size
;Get the from string
PUSH P,DATLNK(VARPTR) ;Data link number
PUSH P,[^D280] ;Maximum length of the string
MOVE T7,SNDSTR(VARPTR) ;Point to the from string
PUSH P,T7 ;Pass as an argument
SETZM 0(T7) ;Zero start of buffer
HRLI T4,0(T7) ;Prepare for the blt
HRRI T4,1(T7)
BLT T4,^D69(T7) ;Zero out the buffer
CALL UN%REA ;(S3/T1)Read the string
ADJSP P,-3 ;Reset the stack
JUMPL T1,R ;An error occurred, return false
;Go through the sender string and set pointers to last node name and the
;User name
MOVE T1,T7 ;Assume sender name
SETZ T2, ;Assume no node name
SETZ T4, ;Assume no quotes
SETZM SCRAT3(VARPTR) ;Assume no personal name
MOVE T10,T7 ;Keep t7 for actual transfer
GOTRU0: SETZ T6, ;[302] Initialize the byte count
CALL SKIPQT ;(T6,T10/T3,T4,T6,T10)Dont parse
; within a quoted string
GOTRU: ILDB T3,T10 ;Get the next byte from sender string
CAIN T3," " ;End of the sender name?
JRST FNDPER ;Yes, check for personal name
CAIN T3,0 ;End of the sender name?
JRST TRANSN ;Yes, copy sender name to sender record
AOS T6 ;[302] increment the byte count
TXNE T4,SNQTS ;Have i seen any special characters?
JRST GOTRU ;[302] yes, skip these tests
CAIN T3,"(" ;Is it a special character?
JRST NEEDQT ;Yes. flag it.
CAIN T3,")"
JRST NEEDQT
CAIN T3,"<"
JRST NEEDQT
CAIN T3,">"
JRST NEEDQT
CAIN T3,"@"
JRST NEEDQT
CAIN T3,","
JRST NEEDQT
CAIN T3,";"
JRST NEEDQT
CAIN T3,"\"
JRST NEEDQT
CAIN T3,QUOTE
JRST NEEDQT
CAIN T3,"["
JRST NEEDQT
CAIN T3,"]"
JRST NEEDQT
CAIE T3,":" ;[302] end of this node name?
JRST GOTRU ;No, get the next character
IBP T10 ;Point to next node or sender name
MOVE T2,T1 ;Make user pointer the node pointer
MOVE T1,T10 ;The new user pointer
JRST GOTRU0 ;Check for the next name
NEEDQT: TXO T4,SNQTS ;[302] set "sender needs quotes" bit
AOS T6 ;[302] increment the byte count
JRST GOTRU ;Continue
; SKIPQT - skips past quoted string if present
; Calling sequence
; SETZ T6 ;clear the count
; MOVE T10,POINTER ;put the pointer in t10
; CALL SKIPQT ;do it
;LOOP: ILDB T3,T10 ;scan non-quoted users
;
; Registers / parameters
; T3 - contains the last character
; T4 - will have snqts set to one if no trailing quote was seen
; T6 - the count of the number of bytes (including quotes)
; T10 - the ildb byte pointer to the string
;
; Return: skip always
SKIPQT: ILDB T3,T10 ;[302] get the next character
CAIE T3,QUOTE ;[302] is it a quote?
RETSKP ;[302] no
SKLOOP: AOS T6 ;[302] yes, increment the count
ILDB T3,T10 ;[302] get next character
CAIN T3,QUOTE ;[302] is it a quote?
JRST SKIPDN ;[302] yes, finish...
JUMPN T3,SKLOOP ;[302] not a quote. is it a null?
;[302] here if no trailing quote, so
MOVNI T3,1 ;[302] back the pointer up. -1 into t3
ADJBP T3,T10 ;[302] t3 now has the backed up pointer
MOVE T10,T3 ;[302] store the updated pointer in t10
LDB T3,T10 ;[302] put the last character in t3
TXO T4,SNQTS ;[302] set the sender needs quotes bit
RETSKP ;[302] all done
SKIPDN: ILDB T3,T10 ;[302] point past the quote
AOS T6 ;[302] increment the count
RETSKP ;[302] return
;Determine if there is a personal name
FNDPER: ILDB T3,T10 ;Get the next character
CAIN T3,0 ;End of the sender name
JRST TRANSN ;Yes, no personal name found
CAIE T3,QUOTE ;Start of the personal name?
JRST FNDPER ;No, check the next character
MOVEM T10,SCRAT3(VARPTR) ;Save pointer to personal name
;Copy sender name to the sender record
TRANSN: MOVEI T5,.RECTX(MSGPTR) ;Sender name field in sender record
HRLI T5,(POINT 7) ;Make it a pointer
MOVEI T3,QUOTE ;Put a quote in t3
PUSH P,T6 ;[302] save the byte count
TXNN T4,SNQTS ;Skip if quotes are needed
TRANS2: ILDB T3,T1 ;Get the next character
IDPB T3,T5 ;[302] place in the sender record
SOJG T6,TRANS2 ;[302] loop until done
;Copy over to the sender record the node name found, if there is one
TRSNOD: POP P,T6 ;[302]restore the byte count
TXNN T4,SNQTS ;Skip if sender needs quotes
JRST TRSNO1 ;No...
MOVEI T3,QUOTE ;Pick up a quote
IDPB T3,T5 ;Write the close-quote in the snder rec
AOS T6 ;[302] include the end-quote in count
TRSNO1: SETZ T4, ;Done with t4
MOVEI T3,"@" ;First, pick up an "at" sign
IDPB T3,T5 ;Place in the sender record
AOS T6 ;Increment the byte count
JUMPE T2,NONODE ;Jump if no node name was found
TRSNO2: ILDB T3,T2 ;Get the next node name character
CAIE T3,":" ;Found the end?
IFSKP.
MOVEI T3,0 ;Yes, make it asciz
IDPB T3,T5 ;Place in sender record
AOS T6 ;Increment the byte count
JRST NUMWRD ;Find the sender record size
ENDIF.
IDPB T3,T5 ;Place in sender record
AOS T6 ;Increment the character count
JRST TRSNO2 ;Get the next character
;No node name in sender string. use the one from mx's data block
NONODE: MOVE T7,CNNBLK(VARPTR) ;Get address of the data block
ADDI T7,20 ;Node name
HRLI T7,(POINT 8) ;Make into a pointer
IBP T7 ;Skip over to the node name
IBP T7
IBP T7
NONOD2: ILDB T1,T7 ;Get the next character
AOS T6 ;Increment the byte count
IDPB T1,T5 ;Place in the sender record
CAIE T1,0 ;Finish?
JRST NONOD2 ;No, get the next character
;Find the number of words in this record
NUMWRD: IDIVI T6,BY2WRD ;Find the number of words
SKIPE T7 ;A partial word?
AOS T6 ;Yes, count as a full word
ADDI T6,.RECHS ;Add the record header size
MOVEM T6,.RECLN(MSGPTR) ;Store the record length
MOVEM MSGPTR,SCRAT4(VARPTR) ;Save for building mail file header
ADD MSGPTR,T6 ;Point msgptr to the next record
ADD WRDCNT,T6 ;Number of words in this message
RETSKP ;And return successfully
SUBTTL MFHEAD BUILD THE DATE AND FROM FIELDS FOR MAIL FILE
;First the date field
MFHEAD: MOVE BUFPTR,STABUF(VARPTR) ;Point to the start of the buffer
MOVEI T2,[ASCIZ /Date: /] ;The first part of the date line
HRLI T2,(POINT 7) ;Make into a pointer
SETZM BUFBYT(VARPTR) ;Number of bytes read so far
DATELP: ILDB T3,T2 ;Get the next byte
CAIN T3,0 ;End of the string?
JRST DATE ;Yes, get the date
IDPB T3,BUFPTR ;Place byte into the buffer
AOS BUFBYT(VARPTR) ;Increment the byte count
JRST DATELP ;Read the next byte
DATE:
TOPS20< MOVE T1,BUFPTR ;Where to place the date and time
SETO T2, ;Current date and time
MOVSI T3,(OT%4YR!OT%SPA!OT%NCO!OT%NSC%!OT%SCL!OT%TMZ) ;Format options
ODTIM%
ERJMP .+1 ;Should not happen
>
TOPS10< PUSH P,BUFPTR ;Where to place the date and time
CALL GETDAT ;(1S)Pick up the date and time
ADJSP P,-1> ;Reset the stack
;Calculate the number of bytes in the date field
BYTCNT: IBP BUFPTR ;Increment the original buffer pointer
AOS BUFBYT(VARPTR) ;Increment the byte count
CAMN BUFPTR,T1 ;Equal the current buffer pointer?
JRST MFHEA2 ;Yes, continue
JRST BYTCNT ;Check again
;Now the from field
MFHEA2: MOVEI T2,[ASCIZ/
From: /] ;The first part of the from: line
HRLI T2,(POINT 7) ;Make into a pointer
FROMLP: ILDB T3,T2 ;Get the next byte
CAIN T3,0 ;End of the string?
JRST SNDCPY ;Yes, copy the sender's name
IDPB T3,BUFPTR ;Deposit the byte in the buffer
AOS BUFBYT(VARPTR) ;Increment the byte count
JRST FROMLP ;Get the next byte
SNDCPY: SKIPN T5,SCRAT3(VARPTR) ;A personal name present?
JRST SNDCP2 ;No, get the user name
MOVEI T1,QUOTE ;Pick up a quote character
IDPB T1,BUFPTR ;Place in the buffer
AOS BUFBYT(VARPTR) ;Increment the byte count
TRSPE2: ILDB T1,T5 ;Get the next character
CAIN T1,QUOTE ;Possible end of personal name?
CALL FINEND ;(/T1)Go find out
JUMPE T1,FINPER ;Finish up the personal name
IDPB T1,BUFPTR ;Deposit the byte in the buffer
AOS BUFBYT(VARPTR) ;Increment the byte count
JRST TRSPE2 ;Get the next byte
FINPER: MOVEI T1," " ;Pick up a blank
IDPB T1,BUFPTR ;Place in the buffer
MOVEI T1,"<" ;Pick up a <
IDPB T1,BUFPTR ;Place in the buffer
AOS BUFBYT(VARPTR) ;Increment the byte count
AOS BUFBYT(VARPTR) ;Increment the byte count
SNDCP2: MOVE T2,SCRAT4(VARPTR) ;Address of sender record
ADDI T2,.RECHS ;Address of from string
HRLI T2,(POINT 7) ;Point to from string
SENDLP: ILDB T3,T2 ;Get the next byte
CAIN T3,0 ;End of the string?
JRST CHKPER ;Yes, add a > if personal name present
IDPB T3,BUFPTR ;Deposit the byte in the buffer
AOS BUFBYT(VARPTR) ;Increment the byte count
JRST SENDLP ;Get the next byte
CHKPER: JUMPE T5,TOSETU ;Skip this is no personal name present
MOVEI T1,">" ;Pick up a >
IDPB T1,BUFPTR ;Place in the buffer
AOS BUFBYT(VARPTR) ;Incrment the byte count
;Set up first part of to: line
TOSETU: MOVEI T2,[ASCIZ/
To: /] ;The first part of the to: line
HRLI T2,(POINT 7) ;Make into a pointer
TOLP: ILDB T3,T2 ;Get the next byte
CAIN T3,0 ;End of the string?
RET ;Yes, return
IDPB T3,BUFPTR ;Deposit the byte in the buffer
AOS BUFBYT(VARPTR) ;Increment the byte count
JRST TOLP ;Get the next byte
;Check for end of the personal name
FINEND: MOVE T2,BUFPTR ;Preserve current buffer pointer
MOVE T4,BUFBYT(VARPTR) ;Preserve current buffer byte count
FINEN2: IDPB T1,BUFPTR ;Deposit byte in buffer
AOS BUFBYT(VARPTR) ;Increment byte count
ILDB T1,T5 ;Get the next byte
CAIN T1,0 ;End of the person name?
JRST RSTPTR ;Yes, reset the pointer and byte count
CAIN T1,QUOTE ;Another quote found?
JRST FINEND ;Yes, start over
CAIN T1," " ;A blank found
JRST FINEN2 ;Yes, continue to look for end
RET ;No, quote is part of personal name
RSTPTR: MOVE BUFPTR,T2 ;Restore the buffer pointer
IBP BUFPTR ;Account for the final quote
AOS T4 ;Account for the final quote
MOVEM T4,BUFBYT(VARPTR) ;Restore the byte count
RET
SUBTTL DSTREC COMPLETES THE MESSAGE AND SENDS IT TO MX
;Do some prelimary setups first
DSTREC: $TRACE <At DSTREC>
SETZM NOMORE(VARPTR) ;Zero means message has more pages
SETOM MSGNUM(VARPTR) ;Page number-1 of current message page
SETZM IDNUM(VARPTR) ;Id number is zero for 1st page of msg
SETZM FILCLO(VARPTR) ;Mail file has not been closed
MOVEI T1,3 ;The # of names/line in the to: list
MOVEM T1,NAMLIN(VARPTR) ;Save for later
SETZM NUMUSR(VARPTR) ;No recipients yet
MOVE T1,STABLK(VARPTR) ;Get address of the first error block
MOVEM T1,INVPTR(VARPTR) ;It's the same as the current error blk
CALL CLRPAG ;(/)Clear the recipient status buffer
NXTSTR: $TRACE <At NXTSTR...>
CAIG WRDCNT,LSTREC ;Room for another record
IFSKP.
CALL SNDMSG ;(/)No, so send off the message to mx
RET ;An error occurred
ENDIF.
PUSH P,DATLNK(VARPTR) ;Data link number
PUSH P,[^D400] ;Maximum length of buffer
MOVE T5,ADRSPA(VARPTR) ;Get the buffer pointer
PUSH P,T5 ;Pass as an argument
SETZM 0(T5) ;Zero first word of the buffer
HRLI T1,0(T5) ;Set up the blt
HRRI T1,1(T5)
BLT T1,^D99(T5) ;Zero the buffer
CALL UN%REA ;(3S/T1)Get the next user
ADJSP P,-3 ;Reset the pointer
JUMPL T1,R ;An error occurred
MOVE T5,ADRSPA(VARPTR) ;Get the buffer pointer
ILDB T2,T5 ;Get the first byte
CAIN T1,1 ;One byte for this recipient?
CAIE T2,0 ;Yes, a null?
SKIPA ;Another recipient string
JRST SNDLST ;No more recipients
AOS NUMUSR(VARPTR) ;Increment the recipient count
MOVE T5,ADRSPA(VARPTR) ;Pointer to recipient string
;The following has been zeroed out. This code dealt with transforming
;a recipient string of the form N1::N2::...NN::USER to SMTP format,
;i.e., @N1,@N2,...NN-1:USER@NN. As it turns out, only the last node
;is needed by MX, so the original string is now transformed to USER@NN
REPEAT 0,<
NXTCHR: SETZ T10, ;Number of characters in user name
MOVE T4,T3 ;Point to start of temporary string
NEXTCH: ILDB T2,T5 ;Get the next character
CAIE T2,":" ;Found a node?
JRST CHKUSR ;No, maybe the user name
;A node has been found. if it is the first node validate it. If valid
;or not the first node, then append node name in temporary buffer with
;a comma
ILDB T2,T5 ;Strip off the second colon
AOS T2,NODCNT(VARPTR) ;Increment the number nodes found
CAIE T2,1 ;The first node?
JRST ADDCOM ;No, add a comma
MOVEI T2,0 ;Make node name into asciz string
MOVE T7,T4 ;Save current end of temp. buffer
IDPB T2,T4 ;Place into the temporary buffer
CALL NODVAL ;(T4/T1)Validate the first node
HRRES T1 ;Make the return code a full word
JUMPGE T1,NODEGD ;Node is valid
CALL INVNOD ;(T7)Node is invalid
RET ;End this session
JRST NXTSTR ;Get the next recipient
NODEGD: MOVE T4,T7 ;Reset end of temporary buffer
ADDCOM: MOVEI T2,"," ;Pick up a comma
IDPB T2,T4 ;Place in the temporary buffer
MOVE T3,T4 ;Pointer to next string component
JRST NXTCHR ;Get the next character of recipient
;Check for user name. if found validate it. if invalid, go for the next
;recipient if valid, map the temporary buffer into the form used by
;MX
CHKUSR: AOS T10 ;Increment number of characters in name
CAIN T2," " ;A user name found?
JRST VLUSER ;Yes, validate it
CAIN T2,0 ;A user name found?
JRST VLUSER ;Yes, validate it
IDPB T2,T4 ;No, place character into temp. buffer
JRST NEXTCH ;Get the next character in user name
;Validate the user name
VLUSER: $TRACE <At VLUSER...>
MOVEI T2,0 ;Make into an asciz string
IDPB T2,T4
PUSH P,T3 ;Destroyed by the call
PUSH P,T4 ;Destroyed
PUSH P,T5 ;Destroyed
PUSH P,T10 ;Number of bytes in user name
PUSH P,T3 ;Point to the user name
MOVE T1,VALUSR(VARPTR) ;Pointer to pobox string (we dont need)
PUSH P,T1 ;Pass as an argument
CALL MX$VAL ;(3S/T1)Validate the user name
ADJSP P,-3 ;Reset the stack
POP P,T5 ;Restore
POP P,T4 ;Restore
POP P,T3 ;Restore
JUMPG T1,TELVAL ;Valid user
CALL INVUSR ;(/)Invalid user, tell the vax
RET ;Error, too many invalid users
JRST NXTSTR ;Get the next recipient
TELVAL: $TRACE <At TELVAL...>
CALL VUSER ;(/)Valid user, tell the vax
RET ;Network error occurred
AOS T1,STAPTR(VARPTR) ;Increment the recipient count
HRRZS T1 ;Isolate the address
ANDI T1,777 ;Get the page offset
CAILE T1,MAXNUM ;End of this error block page?
CALL NXTBUF ;(/)Yes, get another page
MOVEM T3,SCRAT1(VARPTR) ;Pointer to user name, for local to:
MOVE T2,NODCNT(VARPTR) ;Number of nodes in recipient string
CAIN T2,0 ;No node names?
SETOM LOCAL(VARPTR) ;Yes, set local node flag for local to:
;Finished the building of the temporty buffer. now copy it to the recipient
;Record in the format used by mx
SETZ T7, ;Number of bytes in string so far
MOVE T4,WRKBUF(VARPTR) ;Point to start of temporary buffer
HRLI T4,(POINT 7) ;Make it into a pointer
SKIPE T10,NODCNT(VARPTR) ;Nodes in recipient string?
JRST NODFND ;Yes, pick up the first node
;Just a user name in the recipient string, copy over to recipient record
CPYNAM: ILDB T2,T4 ;Get the next character
AOS T7 ;Increment byte count
CAIN T2,0 ;At the end of the user name?
JRST TRSND1 ;Yes, transfer the local node name
IDPB T2,T6 ;Place in the record
JRST CPYNAM ;No, get the next character
TRSND1: MOVEI T2,"@" ;Pick up an ampersand
IDPB T2,T6 ;Place in the record
MOVE T4,NODE7(VARPTR) ;Point to the local node name
TRSND2: ILDB T2,T4 ;Get the next node name character
AOS T7 ;Increment the byte count
IDPB T2,T6 ;Place byte in the record
CAIE T2,0 ;End of the node name?
JRST TRSND2 ;No, get the next character
CALL FINRCD ;(T4,T5,T7)Yes, finish the record
JRST NXTSTR ;Get the next recipient
;At least one node name in recipient string
NODFND: CAIE T10,1 ;Only 1 node name in recipient string?
JRST MRENOD ;No, process differently
;Only 1 node name in recipient string
MOVE T3,T4 ;Remember start of node name
CALL MOVUSR ;(T4,T6,T7)Copy node,user to user@node
CALL FINRCD ;(t4,t5,t7)Get next recipient string
JRST NXTSTR ;Get the next recipient
;N node names in recipient string. copy first n-1 over to recipient record
MRENOD: SOS T10 ;Number of nodes - 1
SEVNOD: MOVEI T2,"@" ;Pick up an @
IDPB T2,T6 ;Place in the recipient record
AOS T7 ;Increment the byte count
NODMOV: ILDB T2,T4 ;Next character from temporary buffer
CAIN T2,"," ;And of this node name?
JRST ENDNOD ;Yes, see if it is the n-1th node name
IDPB T2,T6 ;Place in recipient record
AOS T7 ;Increment the byte count
JRST NODMOV ;Get the next character
ENDNOD: SOSN T10 ;N-1th node?
IFSKP.
MOVEI T2,"," ;No, get a comma
IDPB T2,T6 ;Place in the record
AOS T7 ;Increment the byte count
JRST SEVNOD ;Get the next node
ENDIF.
;The last node name has been found. move the user name over to the recipient
;Record, followed by @node-name
MOVEI T2,":" ;Pick up a colon
IDPB T2,T6 ;Append to the n-1th node name
AOS T7 ;Increment the byte cound
MOVE T3,T4 ;Remember start of final node name
CALL MOVUSR ;(T4,T5,T7)Copy node,user to user@node
CALL FINRCD ;(T4,T6,T7)Get the next recipient
JRST NXTSTR ;Get the next recipient
;Copy the string in the temporary buffer of the form "node,user" to the
;Recipient record in the form "user@node"
MOVUSR: ILDB T2,T4 ;Get next character from temp. buffer
CAIE T2,"," ;End of the last node name?
JRST MOVUSR ;No, try again
NXTONE: ILDB T2,T4 ;Get next user name character
CAIN T2,0 ;End of the user name?
JRST LSTNOD ;Yes, copy the final node name
IDPB T2,T6 ;Place character in recipient record
AOS T7 ;Increment the chartacter count
JRST NXTONE ;Get next user name character
;Copy over the final node name
LSTNOD: MOVEI T2,"@" ;Pick up an @
IDPB T2,T6 ;Place after the user name
CPYOVR: ILDB T2,T3 ;Next character of node name
AOS T7 ;Increment the byte count
CAIN T2,"," ;End of node name?
JRST FINSTR ;Yes, finish recipient string in record
IDPB T2,T6 ;No, place character in record
JRST CPYOVR ;Get the next character
FINSTR: MOVEI T2,0 ;Make recipient string in recipient
IDPB T2,T6 ;Record into an asciz string
RET
>; End of smtp formatting
;Find pointers to the node name (if any) and the recipient name
MOVE T10,T5 ;T10 points to the recipient name
SETZ T7, ;Assume no node name
SETZ T4, ;[302] clear the byte count
SETZ T6, ;[302] clear the byte count for skipqt
CALL SKIPQT ;[302](T6,T10/T3,T4,T6,T10) skip
;[302]the quoted string
JFCL ;[302] skipqt always skips
EXCH T10,T5 ;[302] put things in the right place
EXCH T3,T1 ;[302] use t1 for char
EXCH T4,T6 ;[302] use t4 for count
SKIPA ;[302] skip the ildb
NXTCHR: ILDB T1,T5 ;Get the next recipient string byte
CAIE T1," " ;[302] end of string?
CAIN T1,0 ;End of the string?
JRST CHKNDE ;Yes, check if node name is present
AOS T4 ;[302] increment the byte count
CAIE T1,":" ;Found a node name?
JRST NXTCHR ;No, get the next character
IBP T5 ;Skip over the next colon
MOVE T7,T10 ;Update the node name pointer
MOVE T10,T5 ;Update the recipient pointer
JRST NXTCHR ;Get the next character
;If a node name is present, validate it; otherwise, validate the recipient
CHKNDE: SKIPN T7 ;Node name present?
JRST GETUSR ;No, validate the recipient
MOVE T6,WRKBUF(VARPTR) ;Address of working buffer
HRLI T6,(POINT 7) ;Make into a pointer
MOVE T5,T6 ;[302] save start of working buffer
TRNSND: ILDB T1,T7 ;Get the next node name character
CAIN T1,":" ;End of the node name?
JRST COLFND ;Yes, validate the node name
IDPB T1,T5 ;No, place character in working buffer
JRST TRNSND ;Get the next character
;The node name has been isolated in the working buffer, now validate it
COLFND: SETZ T1, ;Asciz termination character
IDPB T1,T5 ;Make node name asciz
MOVE T7,T6 ;[302] remember start of node name
CALL NODVAL ;(T4/T1)Validate the node name
HRRES T1,T1 ;Make the return code a full word
JUMPGE T1,GETUSR ;Valid node, move recipient to record
CALL INVNOD ;(T7)Mark this recipient as invalid
RET ;Network error occurred, terminate
JRST NXTSTR ;Get the next recipient
;Place the recipient name in the recipient record. if there is no node
;Name then validate the recipient
GETUSR: PUSH P,T4 ;[302] save the byte count
MOVE T6,MSGPTR ;Address of start of this record
ADDI T6,.RECHS ;Address of start of user name string
HRLI T6,(POINT 7) ;Make into a pointer
MOVE T5,T6 ;Save start of recipient field
GETUS2: ILDB T1,T10 ;Get the next recipient character
IDPB T1,T6 ;[302] no, place in recipient record
SOJG T4,GETUS2 ;[302] loop until done
VALIDU: POP P,T4 ;Restore the byte count
MOVE T10,T6 ;Save record position for node name
SETZ T1, ;Asciz termination character
IDPB T1,T6 ;Make recipient name asciz
SKIPE T7 ;Node name present?
JRST TELVAL ;Yes, don't validate recipient name
PUSH P,T4 ;Destroyed by the call
PUSH P,T5 ;Destroyed
PUSH P,T4 ;Number of bytes in user name
PUSH P,T5 ;Point to the user name
MOVE T1,VALUSR(VARPTR) ;Pointer to pobox string (we dont need)
PUSH P,T1 ;Pass as an argument
CALL MX$VAL ;(S3/T1)Validate the user name
ADJSP P,-3 ;Reset the stack
POP P,T5 ;Restore
POP P,T4 ;Restore
JUMPG T1,TELVAL ;Valid user
CALL INVUSR ;(/)Invalid user, tell the vax
RET ;Network error occurred
JRST NXTSTR ;Get the next recipient
;The recipient is valid, send a success message to the vax and then finish
;Building the recipient record
TELVAL: $TRACE <At TELVAL...>
CALL VUSER ;(/)Valid user, tell the vax
RET ;Network error occurred
AOS STAPTR(VARPTR) ;Increment the recipient count
MOVEI T1,"@" ;Pick up an @
IDPB T1,T10 ;Place in the recipient record
SKIPN T7 ;Node name in recipient name?
MOVE T7,NODE7(VARPTR) ;No, use the local node name
TELVA2: ILDB T1,T7 ;Get the next node name character
AOS T4 ;Increment the byte count
IDPB T1,T10 ;Place in the recipient record
CAIE T1,0 ;End of the node name?
JRST TELVA2 ;No, get the next character
CALL FINRCD ;(T4,T6,T7)Finish the record
JRST NXTSTR ;Get the next recipient
NODVAL: $TRACE <At NODVAL...>
PUSH P,T4 ;Node name
PUSH P,[1] ;Local domain
PUSH P,[-1] ;Unknown domain
CALL DB%VD8 ;(3S/T1)Check out the node
ADJSP P,-3 ;Reset the stack
RET
SUBTTL INVNOD INVALID RECIPIENT DETECTED
INVNOD: MOVX T2,INVLND ;Invalid node name detected
SKIPA
INVUSR: MOVX T2,INVLUS ;Invalid recipient
MOVE T1,STAPTR(VARPTR) ;Get pointer of current entry
MOVEM T2,0(T1) ;Place type of error in entry
AOS T1 ;Point to the next word in entry
TXNN T2,INVLND ;Invalid node name?
JRST INVUS2 ;No, go update recipient status address
TRSCHR: ILDB T2,T7 ;Get next node character
IDPB T2,T1 ;Place in the buffer
CAIE T2,0 ;Finished?
JRST TRSCHR ;No, get the next character
MOVE T1,STAPTR(VARPTR) ;Pointer to current entry
ADDI T1,^D3 ;Point to the next entry
INVUS2: MOVEM T1,STAPTR(VARPTR) ;Save for the next invalid user
HRRZS T1 ;Isolate the address
ANDI T1,777 ;Get the page offset
CAILE T1,MAXNUM ;End of this page?
CALL NXTBUF ;(/)Yes, get another page
CALL VUSER ;(/)Fake out the vax
INVRET: RET
RETSKP ;Return true
;Valid user - tell the vax
VUSER: $TRACE <At VUSER...>
PUSH P,T4 ;Destroyed
PUSH P,T5 ;Destroyed
PUSH P,DATLNK(VARPTR) ;Data link number
PUSH P,[1] ;End of message flag
PUSH P,[4] ;Number of bytes in the message
MOVEI T1,SUCMSG(VARPTR) ;Message address
HRLI T1,(POINT 8) ;Make into a pointr
PUSH P,T1 ;Pass as an argument
CALL UN%WRI ;(4S/T1)Do it
ADJSP P,-4 ;Reset the stack
POP P,T5 ;Restore
POP P,T4 ;Restore
JUMPLE T1,R ;An error, return false
RETSKP
;Get an additional page for the recipient status list
NXTBUF: MOVE T2,STAPTR(VARPTR) ;Get address of last entry
SETOM 0(T2) ;Mark it as the last entry
CALL UMP%GET ;(/T1)Get a page
JUMPL T1,[PUSH P,[POINT 7,[ASCIZ /Could not get page at NXTBUF:/]]
PUSHJ P,NMLDIE] ;An error occurred, halt
LSH T1,^D9 ;Change page number to an address
MOVE T2,INVPTR(VARPTR) ;Address of previous page
MOVEM T1,0(T2) ;Place address of current page in it
MOVEM T1,INVPTR(VARPTR) ;Place in current recipient address ptr
; CALL CLRPAG ;(/)Zero out the page
; RET
;Clear the invalid recipient page upon detecting first invalid recipient
CLRPAG: MOVE T1,INVPTR(VARPTR) ;Get starting address of the buffer
SETZM 0(T1) ;Zero the first word
HRLS T1 ;Place starting adr in correct place
AOS T1 ;Form correct destination address
MOVE T2,INVPTR(VARPTR) ;Don't want to use t1 twice in the blt
BLT T1,777(T2) ;Zero the page
MOVE T2,INVPTR(VARPTR) ;Get address of the buffer
AOS T2 ;First word is the link word
HRLI T2,(POINT 8) ;Make into a pointer to 1st recipient
MOVEM T2,STAPTR(VARPTR) ;Save for later
RET
SUBTTL FINRCD FINISH THE RECIPIENT RECORD
FINRCD: $TRACE <At FINRCD...>
MOVEI T1,.DESTN ;Record type
MOVEM T1,.RECTY(MSGPTR) ;Place in the record
AOS T1,MSGRCT(VARPTR) ;Increment number of records
MOVEM T1,.RECNM(MSGPTR) ;Store in the record
MOVE T7,T5 ;Save recipient name for to: list
IDIVI T4,BY2WRD ;Find the number of words in record
SKIPE T5 ;Any partial words?
AOS T4 ;Yes, count as a full word
ADDI T4,.RECHS ;Add in the record header size
MOVEM T4,.RECLN(MSGPTR) ;Place in the record
ADDM T4,WRDCNT ;Save updated count
ADD MSGPTR,T4 ;Pointer to the next record
;Check for room on this line, if already 3 names start a new line
SKIPLE NAMLIN(VARPTR) ;Space for one more?
IFSKP.
MOVE T1,[POINT 7,[ASCIZ/
/]]
DO.
ILDB T2,T1 ;Get the next character
CAIE T2,0 ;The last character?
IFSKP.
MOVEI T2,6 ;Yes, Number of new characters
ADDM T2,BUFBYT(VARPTR) ;Update the byte count
MOVEI T3,3 ;Number of names/line
MOVEM T3,NAMLIN(VARPTR) ;Update the counter
JRST COPYNM ;Continue with the next line
ENDIF.
IDPB T2,BUFPTR ;No, place in the buffer
LOOP. ;Go get another character
ENDDO.
ENDIF.
;Copy the name
COPYNM: ILDB T3,T7 ;Get the next byte
CAIN T3,0 ;End of the string?
JRST COMCPY ;Append a comma
IDPB T3,BUFPTR ;Deposit the next byte
AOS BUFBYT(VARPTR) ;Increment the byte count
JRST COPYNM ;Get the next byte
COMCPY: MOVEM BUFPTR,SCRAT4(VARPTR) ;Remember current position
MOVEI T2,"," ;Get the comma following the name
IDPB T2,BUFPTR ;Place in the buffer
MOVEI T2," " ;Get a blank
IDPB T2,BUFPTR ;Place in the buffer
MOVEI T2,2 ;The number of additional bytes
ADDM T2,BUFBYT(VARPTR) ;Update the byte count
;Update parameters
SOS NAMLIN(VARPTR) ;Update names/line counter
RET
SUBTTL SNDMSG SEND THE MESSAGE TO MX
;Set up the header record
SNDMSG: $TRACE <At SNDMSG...>
AOS T1,MSGNUM(VARPTR) ;Zero means the first page of message
SKIPG T1 ;Is this the first page?
MOVEI T2,.POST ;Yes, indicate so
SKIPE T1 ;Is this the first page?
MOVEI T2,.CONT ;No, indicate so
HRLI T2,.DECNT ;We're the decnet listener
MOVE T4,MSGSTR(VARPTR) ;Point to beginning of the message
MOVEM T2,.PKTYP(T4) ;Store in the record
MOVE T2,IDNUM(VARPTR) ;Pick up message id number
MOVEM T2,.PKID(T4) ;Store in the record
AOS T1 ;Current page of the message
MOVEM T1,.PKSEQ(T4) ;Store in the record
MOVE T1,NOMORE(VARPTR) ;Pick up the last page flag
MOVEI T2,.DONE ;Assume this is the last page
SKIPN T1 ;Is it?
MOVE T2,.MORE ;No, at least one more page
MOVEM T2,.PKSTS(T4) ;Store in the record
MOVE T2,MSGRCT(VARPTR) ;Number of records so far
SKIPE T1 ;Is this correct?
AOS T2 ;No, include the file spec record
MOVEM T2,.PKRCT(T4) ;Place in the record
;If this is the last page of the message, the mail file must be completed
;And the file spec record must be made before sending off the final page
JUMPE T1,SNDOFF ;If 0 then there are more pages
CALL FILSPC ;(/)Fill in the file spec record
CALL FINFIL ;(/)Complete the mail file
RET ;An error occurred
CALL CLOFIL ;(/T1)Close the mail file
CALL SNDOFF ;(/)Send off the final page of the msg
RET ;An error occurred
SETOM FILCLO(VARPTR) ;Indicate the mail file has been closed
CALL CFIRM ;(/)Send the success/failure messages
RET ;An error occurred
RETSKP ;Return successfully
;Send off the message
SNDOFF: $TRACE <At SNDOFF...>
MOVE MSGPTR,MSGSTR(VARPTR) ;Point to start of the message
PUSH P,MSGPTR ;Pass as an argument
PUSH P,[0] ;Required by scan%p
PUSH P,[-1,,[ASCIZ/MX Mail-11 Listener/]] ;Required by scan%p
TOPS20< PUSH P,[SC%WHL] > ;Wheel privs
TOPS10< PUSH P,[IP.JAC] > ;Wheel privs
CALL SCAN%P ;(4S/T1)Send off to MX
ADJSP P,-4 ;Reset the stack
CAIN T1,0 ;Error?
RET ;Yes, return false
;Set up for the next page
SKIPE NOMORE(VARPTR) ;Last page?
RETSKP ;Yes, return true
SETZM MSGRCT(VARPTR) ;No records yet in this message
MOVE T1,.PKID(MSGPTR) ;Get the message id
MOVEM T1,IDNUM(VARPTR) ;Store for later
RETSKP ;Return true
;The last page of the message has been completed, send it off
SNDLST: $TRACE <At SNDLST...>
SETOM NOMORE(VARPTR) ;This is the last page of the message
CALL SNDMSG ;(/)Send it off
RET ;An error occurred
RETSKP ;Return true
SUBTTL FILSPC CREATE THE FILE SPEC RECORD
FILSPC: $TRACE <At FILSPC...>
AOS T1,MSGRCT(VARPTR) ;Pick up the number of records
MOVEM T1,.RECNM(MSGPTR) ;Store in the record
MOVEI T1,.FLSPC ;File spec record
MOVEM T1,.RECTY(MSGPTR) ;Store in the record
;Copy file name over to spec record
SETZ T4, ;Number of bytes in the file name
MOVE T2,MAIPTR(VARPTR) ;Point to the file name
MOVE T3,[POINT 7,.RECTX(MSGPTR)] ;Point to record location
COPNAM: ILDB T1,T2 ;Get the next byte
IDPB T1,T3 ;Place this byte in the record
AOS T4 ;Increment the byte count
CAIE T1,0 ;Is this the end?
JRST COPNAM ;No, get the next character
;Find the record size
IDIVI T4,BY2WRD ;Find the number of words in file spec
SKIPE T5 ;Any partial words
AOS T4 ;Yes, count as a full word
ADDI T4,.RECHS ;Add size of the file header
MOVEM T4,.RECLN(MSGPTR) ;Store length in record
RET
SUBTTL FINFIL COMPLETE THE MAIL FILE
;Get the mailed to: list from the vax
FINFIL: $TRACE <At FINFIL...>
SETZM EOFMES(VARPTR) ;End of vax message not yet found
MOVE BUFPTR,SCRAT4(VARPTR) ;Get rid of last comma, blank
MOVEI T1,15 ;Replace the comma
IDPB T1,BUFPTR ;With a carriage return
MOVEI T1,12 ;Replace the blank
IDPB T1,BUFPTR ;With a line feed
MOVE T6,WRKBU2(VARPTR) ;Prepare for the call
HRLI T6,(POINT 8) ;Make it an 8 bit byte pointer
CALL REALIN ;(T6)Read "MAILED-T0: line, copy
;to buffer...
RET ;An error occurred
;Get the subject line from the vax
MOVE T6,WRKBUF(VARPTR) ;Get the working buffer address
HRLI T6,(POINT 8) ;Make into an 8 bit byte pointer
CALL REALIN ;(T6)Copy the subject: to the buffer
RET ;An error occurred
;Copy the subject line
MOVEI T2,[ASCIZ/Subject: /] ;Address of the string
HRLI T2,(POINT 7) ;Make into a pointer
SUBJLP: ILDB T3,T2 ;Get the next byte
CAIN T3,0 ;End of the string?
JRST SUBCOP ;Yes, save the updated buffer pointer
IDPB T3,BUFPTR ;Store this byte in the buffer
AOS BUFBYT(VARPTR) ;Increment the byte count
JRST SUBJLP ;Get the next byte
SUBCOP: MOVE T7,WRKBUF(VARPTR) ;Point to the buffer to be copied
CALL CPYBUF ;(T7)Copy over the subject
;Copy the mailed to: line to the buffer
MOVEI T2,[ASCIZ/Mailed-to: /] ;[304] line to be copied
HRLI T2,(POINT 7) ;Make into a pointer
MAILP: ILDB T3,T2 ;Get the next byte
CAIN T3,0 ;End of the string?
JRST SAVEPT ;Yes, save the updated buffer pointer
IDPB T3,BUFPTR ;Store this byte in the buffer
AOS BUFBYT(VARPTR) ;Increment the byte count
JRST MAILP ;Get the next byte
SAVEPT: MOVE T7,WRKBU2(VARPTR) ;Address of the mailed to: list
CALL CPYBUF ;(T7)Copy over to the buffer
;Insert two blank lines
MOVEI T7,[ASCIZ/
/]
CALL CPYBUF ;(T7)Copy over to the buffer
MOVEI T1,2 ;Number of new characters
ADDM T1,BUFBYT(VARPTR) ;Update the buffer character count
;Copy the buffer to the mail file
MOVE T1,STABUF(VARPTR) ;Point to start of buffer
PUSH P,FILNB(VARPTR) ;File number of the mail file
PUSH P,T1 ;Point to start of the buffer
MOVE T1,BUFBYT(VARPTR) ;Number of bytes to copy
PUSH P,T1 ;Pass as an argument
PUSH P,[0] ;No error buffer
CALL UF%WRI ;(4S/T1)Write to the mail file
ADJSP P,-4 ;Reset the stack
;Now copy the message to the mail file
CPYMES: SETZM BUFBYT(VARPTR) ;Number of bytes in buffer so far
HRR T6,STABUF(VARPTR) ;Address to read next msg line into
HRLI T6,(POINT 8) ;Make it an 8 bit byte pointer
CALL REALIN ;(T6)Read the next line
RET ;An error occurred, return false
SKIPE EOFMES(VARPTR) ;End of message?
JRST CPYDSH ;Yes, add dashes at end of the message
MOVE T1,STABUF(VARPTR) ;Point to the start of the buffer
MOVE T2,BUFBYT(VARPTR) ;The number of bytes to copy
PUSH P,FILNB(VARPTR) ;File number of the mail file
PUSH P,T1 ;Start of the buffer
PUSH P,T2 ;Number of bytes to copy
PUSH P,[0] ;No error buffer
CALL UF%WRI ;(4S/T1)Write the buffer to the
;mail file
ADJSP P,-4 ;Reset the stack
JRST CPYMES ;Get the next line
CPYDSH: MOVE T1,STABUF(VARPTR) ;Point to the start of the buffer
MOVE T6,T1 ;Copy for the destination of the blt
HRLI T6,FINDSH ;Source of the blt
BLT T6,^D3(T1) ;Copy dashes to the buffer
MOVEI T2,^D13 ;Number of bytes in this line
PUSH P,FILNB(VARPTR) ;File number of the mail file
PUSH P,T1 ;Start of the buffer
PUSH P,T2 ;Number of bytes to copy
PUSH P,[0] ;No error buffer
CALL UF%WRI ;(4S/T1)Write the buffer to the
;mail file
ADJSP P,-4 ;Reset the stack
RETSKP ;Finished, return true
FINDSH: ASCIZ/ --------
/
SUBTTL REALIN READS NEXT LINE FROM VAX AND PLACES IN THE MAIL FILE
;First, read in the line
;This routine is called with t6 pointing to where the data is to be read
;To (it must be an 8 bit byte pointer)
REALIN: PUSH P,DATLNK(VARPTR) ;The data link number
PUSH P,[^D400] ;The number of words max
PUSH P,T6 ;Where the line is to be read to
SETZM 0(T6) ;Zero the first word of the buffer
HRLI T7,0(T6) ;Prepare for the blt
HRRI T7,1(T6)
BLT T7,^D99(T6) ;Zero out the buffer
CALL UN%REA ;(3S/T1)Get the 8 bit line from the vax
ADJSP P,-3 ;Reset the stack
JUMPL T1,R ;An error, return false
MOVE T7,T6 ;Save for the sout
;Translate the 8 bit line to 7 bits
HRR T5,T6 ;Get the address for the 7 bit line
HRLI T5,(POINT 7) ;Make it a 7 bit pointer
CAIE T1,1 ;Message 1 byte in length?
JRST TRNSFR ;No, not end of message
ILDB T2,T6 ;Yes, get the byte
CAIE T2,0 ;A null?
JRST TRNSF2 ;No, change to 7 bits
SETOM EOFMES(VARPTR) ;Yes, end of message
RETSKP ;Return true
TRNSFR: ILDB T2,T6 ;Get the next byte
CAIN T2,0 ;End of the line?
JRST ENDLN ;Yes, finish up
TRNSF2: IDPB T2,T5 ;Place in the 7 bit line
AOS BUFBYT(VARPTR) ;Increment the byte count
JRST TRNSFR ;Get the next byte
;Finish the line with a carriage return, line feed
ENDLN: MOVEI T2,15 ;Get the carriage return
IDPB T2,T5 ;Place in the working buffer
MOVEI T2,12 ;Get the line feed
IDPB T2,T5 ;Place in the working buffer
MOVEI T2,0 ;Make it an asciz string
IDPB T2,T5 ;Place in the working buffer
MOVEI T2,2 ;Number of additional bytes in buffer
ADDM T2,BUFBYT(VARPTR) ;Update the byte count
RETSKP
;Copy the working buffer to the buffer
CPYBUF: HRR T2,T7 ;Get address of the working buffer
HRLI T2,(POINT 7) ;Make into a pointer
BUFLP: ILDB T3,T2 ;Get the next working buffer byte
CAIN T3,0 ;End of the string?
RET ;Yes, return
IDPB T3,BUFPTR ;Store this byte in the buffer
JRST BUFLP ;Get the next byte
SUBTTL CFIRM SEND SUCCESS/FAILURE MESSAGES
CFIRM: $TRACE <At CFIRM...>
MOVN T7,NUMUSR(VARPTR) ;Get the number of recipients
MOVE T10,STABLK(VARPTR) ;Address of the recipient status buffer
MOVE T6,T10 ;Save in case there is more than 1 page
AOS T10 ;Skip over the link word
DONEXT: MOVE T1,0(T10) ;Get the next recipient status word
JUMPE T1,CHKSUC ;Zero means recipient received mail
SKIPG T1 ;The last entry of this page?
CALL GTNXBF ;(T6/T10)Yes, get the next page of
;statuses
CALL ERRRCT ;(/)Inform vax of error
JRST CFIRET ;Network error occurred
JRST CHKNXT ;Check status of next recipient
CHKSUC: CALL SUCRCT ;(/)Inform vax recipient received mail
JRST CFIRET ;Network error occurred
CHKNXT: AOJN T7,DONEXT ;Check status of next recipient
CALL RLSEPG ;(T7)Release any recipient status pages
RETSKP ;Finished, return true
CFIRET: RET ;Network error occurred, release
;Recipient status pages later
;Get the address of the next recipient status page
GTNXBF: MOVE T10,0(T6) ;Get the address from the current page
MOVE T6,T10 ;Save in case there is another page
AOS T10 ;Skip over the link word
RET
;Release any recipient status pages
RLSEPG: MOVE T1,STABLK(VARPTR) ;Get address of the resident page
MOVE T7,0(T1) ;Get contents of the link word
RLSEP1: SKIPN T7 ;Is there any other pages?
RET ;No, so quit
MOVE T1,T7 ;Get a copy of the address
MOVE T7,0(T7) ;Get the link word of this page
LSH T1,-^D9 ;Change address to page number
PUSH P,T1 ;Pass the page number as an argument
CALL UMP%RE ;(1S/T1)Release the page
ADJSP P,-1 ;Reset the stack
JUMPL T1,[PUSH P,[POINT 7,[ASCIZ /Error releasing page at RLSEP1:/]]
PUSHJ P,NMLDIE ] ;Error in releasing the page
JRST RLSEP1 ;Release the next page, if any
SUBTTL ERRRCT SEND INVALID USER OR NODE MESSAGE
ERRRCT: $TRACE <At ERRRCT...>
INVND2: PUSH P,DATLNK(VARPTR) ;Data link number
PUSH P,[1] ;End of message flag
PUSH P,[4] ;Number of bytes in the error message
MOVEI T1,FAIMSG(VARPTR) ;Error message address
HRLI T1,(POINT 8) ;Make it into a pointer
PUSH P,T1 ;Pass as an argument
CALL UN%WRI ;(4S/T1)Tell the vax
ADJSP P,-4 ;Reset the stack
JUMPLE T1,ENINN ;An error, abort the link
MOVE T1,0(T10) ;Get the error flag
TXNN T1,INVLND ;Invalid node name?
JRST IVUSER ;No, invalid user
MOVE T1,WRKBU2(VARPTR) ;Address of buffer to be sent to vax
HRLI T1,ERMSG3 ;Address of first part of message text
BLT T1,10(T1) ;Copy to the buffer
MOVE T1,WRKBU2(VARPTR) ;Address of buffer to be sent to vax
HRLI T1,(POINT 8) ;Make into a pointer
ADDI T1,10 ;Point to the correct word
IBP T1 ;Skip over this byte
MOVE T3,T10 ;Address of current invalid node entry
AOS T3 ;Address of invalid node name
HRLI T3,(POINT 8) ;Make into a pointer
MOVEI T5,^D33 ;Number of bytes in message so far
CHSIZE: ILDB T2,T3 ;Get the next 7 bit byte
CAIN T2,0 ;End of the string?
JRST SNDNOD ;Yes, send to the vax
IDPB T2,T1 ;No, place in 8 bit byte name buffer
AOS T5 ;Increment byte count
JRST CHSIZE ;Get the next byte
SNDNOD: $TRACE <At SNDNOD...>
PUSH P,DATLNK(VARPTR) ;Get the data link number
PUSH P,[1] ;End of message flag
PUSH P,T5 ;The length of the message
MOVE T1,WRKBU2(VARPTR) ;Point to the message
HRLI T1,(POINT 8) ;Make into a pointer
PUSH P,T1 ;Pass as an argument
CALL UN%WRI ;(4S/T1)Send the message off
ADJSP P,-4 ;Adjust the stack pointer
JUMPLE T1,ENINN ;An error occurred, return false
PUSH P,DATLNK(VARPTR) ;Data link
PUSH P,[1] ;End of message
PUSH P,[1] ;Message length
MOVEI T1,[EXP 0] ;The message
HRLI T1,(POINT 8) ;Make it into a pointer
PUSH P,T1 ;Pass as an argument
CALL UN%WRI ;(4S/T1)Tell the vax
ADJSP P,-4 ;Reset the stack
JRST COMCH2 ;Check for another invalid node or user
IVUSER: $TRACE <At IVUSER...>
MOVE T1,WRKBU2(VARPTR) ;Address of buffer to be sent to vax
HRLI T1,ERMSG1 ;Address of first part of message text
HRRZ T3,WRKBU2(VARPTR) ;Address for the blt
BLT T1,12(T3) ;Copy to the buffer
MOVE T1,WRKBU2(VARPTR) ;Address of buffer to be sent to vax
HRLI T1,(POINT 8) ;Make into a pointer
ADDI T1,12 ;Point to the correct word
IBP T1 ;Skip over this byte
IBP T1 ;Skip over this byte
NXTPT2: MOVEI T5,^D42 ;Size of the message so far
MOVE T3,NODE7(VARPTR) ;Pointer to node name
NXTPT3: ILDB T2,T3 ;Get the next character
CAIN T2,0 ;End of the node name?
JRST INVMSG ;Yes, send off the message
AOS T5 ;No, increment the byte count
IDPB T2,T1 ;Place in the buffer
JRST NXTPT3 ;Get the next character
INVMSG: $TRACE <At INVMSG...>
PUSH P,DATLNK(VARPTR) ;Data link
PUSH P,[1] ;End of message
PUSH P,T5 ;Message length
MOVE T1,WRKBU2(VARPTR) ;Address of the buffer
HRLI T1,(POINT 8) ;Make into a pointer
PUSH P,T1 ;Pass as an argument
CALL UN%WRI ;(4S/T1)Tell the vax
ADJSP P,-4 ;Reset the stack
JUMPLE T1,ENINN ;Network error, abort the link
PUSH P,DATLNK(VARPTR) ;Data link
PUSH P,[1] ;End of message
PUSH P,[1] ;Message length
MOVEI T1,[EXP 0] ;The message
HRLI T1,(POINT 8) ;Make it into a pointer
PUSH P,T1 ;Pass as an argument
CALL UN%WRI ;(4S/T1)Tell the vax
ADJSP P,-4 ;Reset the stack
JUMPLE T1,ENINN ;Network error
COMCHK: AOS T10 ;Address of the next status entry
SKIPA ;Go return
COMCH2: ADDI T10,3 ;Address of the next status entry
RETSKP ;Return true
ENINN: RET ;Return false, a network error occurred
;Inform vax of successful recipients
SUCRCT: PUSH P,DATLNK(VARPTR) ;Data link number
PUSH P,[1] ;End of message flag
PUSH P,[4] ;Size of the message
MOVEI T2,SUCMSG(VARPTR) ;Message address
HRLI T2,(POINT 8) ;Make into a pointer
PUSH P,T2 ;Pass as an argument
NXTSMG: $TRACE <At NXTSMG...>
CALL UN%WRI ;(4S/T1)Send the message
ADJSP P,-4 ;Reset the stack
JUMPLE T1,R ;Return now if network error occurred
AOS T10 ;Address of next status entry
RETSKP ;And return
SUBTTL DISCON - DISCONNECT THE CONNECTION
;Close the link
DISCON: $TRACE <At DISCON...>
PUSH P,DATLNK(VARPTR) ;Pass the data link number
PUSH P,[0] ;No optional data
PUSH P,[0] ;No optional data pointer
CALL UN%CLO ;(3S/T1)Close the link
ADJSP P,-3 ;Reset the stack
JUMPLE T1,FORDIS ;On error, abort the link
RET ;And return
;Fordis aborts the link due to any unrecoverable error
FORDIS: $TRACE <At FORDIS...>
PUSH P,DATLNK(VARPTR) ;Data link
PUSH P,[.DCX11] ;Undefined error
PUSH P,[0] ;No optional data
PUSH P,[0] ;No optional data pointer
CALL UN%ABO ;(4S/T1)Abort the link
ADJSP P,-4 ;Reset the stack
RET ;And return
;Clsfil closes and deletes the mail file due to an unrecoverable error
CLSFIL: $TRACE <At CLSFIL...>
PUSH P,FILNB(VARPTR) ;File number of the mail file
PUSH P,[1] ;Abort the file
PUSH P,[0] ;No error string
CALL UF%CLO ;(3S/T1)Close and delete the mail file
ADJSP P,-3 ;Reset the stack
RET ;And return
;Clofil closes the mail file prior to the last message page being sent to mx
CLOFIL: $TRACE <At CLOFIL...>
PUSH P,FILNB(VARPTR) ;File number of the mail file
PUSH P,[0] ;Do not abort the file
PUSH P,[0] ;No error string
CALL UF%CLO ;(3S/T1)Close the mail file
ADJSP P,-3 ;Reset the stack
RET ;And return
;Release the space allocated to the mail file spec
RELMAI: $TRACE <At RELMAI...>
HRRZ T1,MAIPTR(VARPTR) ;Address of the space
PUSH P,T1 ;Pass as an argument
CALL RELASC ;(1S/T1)Release it
ADJSP P,-1 ;Reset the stack
RET
;This routine informs mx of any errors that occurred
;T1 contains the error code
;T2 contains the node name
SMXERR: PUSH P,T1 ;Pass the error code
PUSH P,[0] ;No message id.
PUSH P,T2 ;Pass the optional data
PUSH P,[0] ;No reject code
CALL ELOG ;(4S/)Log it
ADJSP P,-4 ;Reset the stack pointer
RET ;Return +1 always
RSKP: AOS 0(P)
R: RET
END