Trailing-Edge
-
PDP-10 Archives
-
bb-ev83b-bm_longer
-
tcpip-sources/sndmsg.mac
There are 11 other files named sndmsg.mac in the archive. Click here to see a list.
TITLE SNDMSG - Routines to send local and network TTY messages
SUBTTL David Eppstein/DE/KSL/MRC/WHP4
SEARCH MONSYM,MACSYM,SNDDEF
EXTERN $WAKE
EXTERN $GTLCL,$RMREL
ASUPPRESS
SALL
IFNDEF OT%822,OT%822==:1
; Definitions and Storage
A=:1 ;Temporary AC's for JSYS use etc
B=:2
C=:3
D=:4
ADR=10 ;Pointer to current address block
ABLOCK=11 ;Pointer to argument block
FP=:15 ;TRVAR frame pointer
CX=:16 ;Scratch for MACREL
P=:17 ;Main stack pointer
BUFLEN==MAXCHR/5 ;Length of command buffers (for long msgs)
PDLEN==100 ;Length of pushdown stack
; Macros for returning error strings and codes
DEFINE RETSTR (ERTEXT,ERCODE,OP<JRST>) <
OP [ HRROI A,[ASCIZ\ERTEXT\]
MOVX C,ERCODE
RET ]
>
; Storage allocation
.PSECT DATPAG ;Paged storage
BUFFER: BLOCK 1000 ;Random text storage etc (must be whole page)
BUFPAG==BUFFER/1000 ;The associated page number
.ENDPS
.PSECT CODE ;Rest of this file is pure code
; $SEND - Send a terminal message to multiple recipients
; Call with A/pointer to ASCIZ message text
; B/list of recipients to send to
; C/argument block
; Returns +1/Failed, A/error string
; B/points to failed recipient
; C/error code (TTXxxx defined in SNDDEF)
; +2/Success, A, B, and C changed
;
; Format of the recipient list:
; Each recipient block is in the form of a header word possibly
; followed by some data words. The format of the header word is
; RC%TYP,,RC%NXT where RC%TYP is a code for the type of recipient
; coded for by this block, and RC%NXT is the next recipient.
; End the list with a 0 RC%NXT field. Values for RC%TYP are:
; RC.TTY - Recipient is a local terminal.
; Data is the terminal number (without .TTDES)
; RC.USR - Recipient is a local user - data is user number.
; RC.ALL - Send to all local users (no data).
; RC.NET - Send to a net user. Data are two word-aligned
; ASCIZ strings for the user and host names.
;
; Example: to send to TTY4, FMF, and CSD.KDO@SCORE one might have:
; RBLOCK: RC.TTY,,RBLK0
; 4 ;TTY 4 (not 400004)
; RBLK0: RC.USR,,RBLK1
; 500000,,137 ;FMF's user number (use RCUSR%)
; RBLK1: RC.NET,,0
; ASCIZ/CSD.KDO/ ;Net user name (CSD.KDO)
; ASCIZ/SCORE/ ;Net host name (SCORE)
;
;
; Format of the argument block:
; Word 0 (.SDPID): PID for IPCF messages. Set to zero to make $SEND
; create a new PID - it will be filled in if created.
; Word 1 (.SDFLG): Flags for the IPCF send server. Defined flags:
; 1B0 (T%USER) - "User program features" like typing the status
; of a send to user with multiple ttys
; 1B1 (T%RAFT) - Obey REFUSE SYS after this message
; 1B2 (T%HDR) - Don't supply a message header (needs WHEEL)
; 1B3 (T%RSYS) - Obey REFUSE SYS always
$SEND:: SAVEAC <D,ADR,ABLOCK,CX> ;Don't mung anything for caller
TRVAR <MSPTR,QUEJFN> ;Make some pseudo-globals
SETZM QUEJFN ;So nobody thinks random crud is a JFN
MKPTR (A) ;Turn into a byte pointer
MOVEM A,MSPTR ;Get message text pointer
MOVE ADR,B ;Get address block
MOVE ABLOCK,C ;Get argument block
DO.
CALL SNDONE ;Send one message
IFSKP.
MOVE B,.SDFLG(ABLOCK) ;Done, get SNDSRV flags
TXZN B,T%RAFT ;Obey REFUSE SYS after that message
IFSKP.
TXON B,T%RSYS ;Yes, set flag for that
MOVEM B,.SDFLG(ABLOCK) ;Save changed flag word
ENDIF.
LOAD ADR,RC%NXT,(ADR) ;Done, get next
JUMPN ADR,TOP. ;And loop back with it
ELSE.
CALL MQUEUE ;Failed, queue net sends
MOVE B,ADR ;Get address block back
RET ;And return failure
ENDIF.
ENDDO.
CALL MQUEUE ;Done, finish queueing net sends
MOVE A,MSPTR ;Get message text pointer again
MOVE B,ADR ;Get final value in ADR (should be 0)
MOVE C,ABLOCK ;Get address block address
RETSKP ;Return success with them
; Finish queueing net sends
MQUEUE: SAVEAC <A,B,C> ;Don't mung error code or whatever
SKIPN QUEJFN ;Are we queueing anything?
RET ;No, done already
;; Finish creating the queued mail file
HRROI A,BUFFER ;Get buffer back
FMSG <
Date: > ;Yes, start text
SETO B,
MOVX C,OT%DAY!OT%SPA!OT%TMZ!OT%SCL!OT%822 ; RFC 822 standard date/time
ODTIM%
FMSG <
From: >
CALL .DIRST ;Put in my username
FMSG <@>
PUSH P,A
CALL $GTLCL ;Local host name
IFNSK.
POP P,A
RETSTR <Couldn't get local host name>,TTXNET
ENDIF.
POP P,A
CALL $RMREL
MOVE A,QUEJFN
HRROI B,BUFFER ;Get buffer back
SETZ C, ;Until null
SOUT% ;Start making file
FMSG <
>
MOVE B,MSPTR ;Get pointer to message text
SETZ C, ;Ending on null
SOUT% ;Send it off
CLOSF% ;Close the file
NOP
CALLRET $WAKE ;Wake up MMailr and return
; SNDONE - Send one message
; returns +1/failure, A and C set up; +2/success
SNDONE: LOAD A,RC%TYP,(ADR) ;Get send type
CAIG A,RC.NET ;In range?
IFSKP.
HRROI A,[ASCIZ/Unknown function code/]
MOVEI C,TTXUNK ;No, get error string and code
RET ;Return failure
ENDIF.
CAIN A,RC.NET ;If it's a net send
JRST SNDNET ;Then send that way
JRST SNDLOC ;Else it's a local send
; Here to make error string for JSYS error and return
JSRET: HRROI A,BUFFER+200 ;Use a likely buffer
HRLOI B,.FHSLF ;With ourself
MOVEI C,40*5-1 ;Number of characters available
ERSTR% ;Copy error string
NOP
NOP
HRROI A,BUFFER+200 ;Now point to the string we made
MOVX C,TTXNET ;Random network error (not called from SNDLOC)
RET
; Sending a Local Message
SNDLOC: LOAD A,RC%TYP,(ADR) ;Fetch type of field we parsed
MOVE A,[ SIXBIT/SNDLIN/
SIXBIT/SNDUSR/
SIXBIT/SNDALL/ ](A)
MOVEM A,BUFFER+SN$HDR ;Set up appropriate function code
MOVE A,1(ADR) ;Retrieve word of data (garbage for SNDALL)
MOVEM A,BUFFER+SN$DAT ;Set up data
MOVE A,.SDFLG(ABLOCK) ;Get flags for IPCF
MOVEM A,BUFFER+SN$FLG ;Set them
HRROI A,BUFFER+SN$MSG ;Into the appropriate place in the IPCF page
MOVE B,MSPTR ;From message pointer given to us
CALL MOVSTR ;Copy the message
MOVE D,.SDPID(ABLOCK) ;With PID we were given
CALL DOIPCF ;Go send it off
IFNSK.
MOVEM D,.SDPID(ABLOCK) ;Failed, copy PID back anyway
RET ;Give fail return
ENDIF.
MOVEM D,.SDPID(ABLOCK) ;Succeeded, copy PID back
SKIPN BUFFER+SN$HDR ;Header word is -1 on errors
IFSKP.
HRROI A,BUFFER+SN$STR ;Point to error string
MOVE C,BUFFER+SN$ERR ;And get error code returned
RET ;Return failure
ENDIF.
MOVE A,BUFFER+SN$TTY ;Fetch number of terminals sent to
CAIG A,1 ;One or none?
RETSKP ;Yes, done (none?? should be error)
MOVE A,.SDFLG(ABLOCK) ;Get argument flags
TXNN A,T%USER ;We running a user program?
RETSKP ;No, be quiet
;; Multiple jobs with T%USER set - give status of each
LOAD A,RC%TYP,(ADR) ;Get address type
CAIE A,RC.ALL ;Is it to *?
IFSKP. ;Yes, "* has multiple jobs" is ugly, so:
TMSG <Status of system-wide send:
>
ELSE.
MOVX A,.PRIOU ;To the terminal
MOVE B,ADR ;With current address
CALL $WTRCP ;Write recipient name
TMSG < has multiple jobs:
> ;Start message
ENDIF.
MOVN D,BUFFER+SN$TTY ;Fetch and negate no. of terminals pawed over
HRLZS D ;Swap and clear
DO.
TMSG < > ;Space over for pretty
MOVEI A,.PRIOU ;A to the terminal
HRRZ B,BUFFER+SN$TTY+1(D)
ADDI B,.TTDES ;Make TTY number into a device designator
DEVST% ;Write device name, e.g. TTY6
ERJMP .+1
TMSG <: -- > ;Add a colon and separating dashes
HLRZ B,BUFFER+SN$TTY+1(D) ;Fetch status flag for that line
HRRO A,[ [ASCIZ/refused/]
[ASCIZ/ok/]
[ASCIZ/timed out/]
[ASCIZ/refused/] ]+1(B)
PSOUT% ;Print out the status
TMSG <
> ;End with a CRLF
AOBJN D,TOP. ;Loop over the list
ENDDO.
RETSKP
; DOIPCF - send an IPCF page to the send server and await the response
; call with BUFFER/message, D/PID of this process (zero if none)
; returns +1/failure, +2/success, reply page in BUFFER
PACLEN==7 ;Length of MSEND/MRECV packet
DOIPCF: STKVAR <SRVPID,<SNDARG,4>,<PACKET,PACLEN>>
MOVX A,IP%CPD ;Get create pid flag into place
SKIPE D ;Do we already have a pid?
SETZ A, ;Yes, no special flags needed
MOVEM A,.IPCFL+PACKET ;Set up flag word
MOVEM D,.IPCFS+PACKET ;We are the sender
SETZM .IPCFR+PACKET ;INFO is the receiver
MOVEI A,SNDARG
HRLI A,4
MOVEM A,.IPCFP+PACKET ;Set up pointer to argument block
MOVX A,.IPCIW
MOVEM A,.IPCI0+SNDARG ;Get pid for this name
SETZM .IPCI1+SNDARG ;No duplicate
DMOVE A,[ASCIZ/SNDSRV/] ;Point to string for SNDSRV's PID name
DMOVEM A,.IPCI2+SNDARG ;Stash the id
MOVEI A,PACLEN
MOVEI B,PACKET
MSEND% ;Ask info for server PID, maybe create our PID
RETSTR <Error while sending to INFO>,TTXIPC
MOVE D,.IPCFS+PACKET ;Fetch our PID in case it was created
MOVEM D,.IPCFR+PACKET ;We are receiver this time
SETZM .IPCFL+PACKET ;Sender is INFO
MOVEI A,PACLEN
MOVEI B,PACKET
MRECV% ;Receive reply from INFO
RETSTR <Error receiving from INFO>,TTXIPC
LDB A,[POINT 6,.IPCFL+PACKET,29] ;Get INFO error code field
IFN. A
CAIN A,76 ;Couldn't find it?
RETSTR <Server not running>,TTXIPC
RETSTR <INFO error other than server not running>,TTXIPC
ENDIF.
MOVE A,.IPCI1+SNDARG
MOVEM A,SRVPID ;Store server's PID
MOVX A,IP%CFV
MOVEM A,.IPCFL+PACKET ;Sending a page of data
MOVEM D,.IPCFS+PACKET ;We are the sender
MOVE A,SRVPID
MOVEM A,.IPCFR+PACKET ;The server is the receiver
MOVEI A,BUFPAG ;From the data page
HRLI A,1000 ;A whole page full
MOVEM A,.IPCFP+PACKET
MOVEI A,PACLEN
MOVEI B,PACKET
MSEND% ;Send off the request
RETSTR <Error sending to server>,TTXIPC
MOVX A,IP%CFV
MOVEM A,.IPCFL+PACKET ;Receiving a page of data
MOVE A,SRVPID
MOVEM A,.IPCFS+PACKET ;From the server
MOVEM D,.IPCFR+PACKET ;To our own PID
MOVEI A,BUFPAG ;Back to the same data page
HRLI A,1000
MOVEM A,.IPCFP+PACKET
MOVEI A,PACLEN
MOVEI B,PACKET
MRECV% ;Receive a reply
RETSTR <Error receiving from server>,TTXIPC
RETSKP
; SNDNET - Send a Network Message
; returns +1/failure, A and C set for return; +2/success
SNDNET: SKIPE A,QUEJFN ;Do we have a queued mail file yet?
JRST NETRCP ;Yes, just add recipient
HRROI A,BUFFER ;Into a free place
HRROI B,[ASCIZ/MAILQ:[--QUEUED-MAIL--].NEW-/]
SETZ C,
SOUT% ;Start making name
PUSH P,A ;Create frame to save string pointer
GTAD% ;Now output date/time
MOVE B,A
MOVE A,(P)
MOVEI C,^D8 ;Output in octal
NOUT%
RETSTR <Couldn't make name for queued mail file>,TTXNET
FMSG <-SNDMSG-J>
MOVEM A,(P) ;Update saved string pointer
GJINF% ;Get my job number
POP P,A ;Get string pointer back
MOVE B,C ;Get job number in B
MOVEI C,^D10 ;Output in octal
NOUT%
RETSTR <Couldn't make name for queued mail file>,TTXNET
FMSG <.-1;P770000> ;Next generation, set protection
MOVX A,GJ%SHT!GJ%FOU ;File for output
HRROI B,BUFFER ;With nice file name
GTJFN% ;Get handle on queue file
RETSTR <Couldn't get handle on queued mail file>,TTXNET
MOVX B,FLD(7,OF%BSZ)!OF%WR ;Writing
OPENF% ;Open it up
RETSTR <Couldn't open queued mail file>,TTXNET
MOVEM A,QUEJFN ;Save for later
HRROI A,BUFFER ;Into buffer space
FMSG <
=DELIVERY-OPTIONS:SEND
_> ;This is a send, from someone
CALL $GTLCL ;Get local host name
RETSTR <Couldn't get local host name>,TTXNET
FMSG <
> ;CRLF (still in buffer)
CALL .DIRST ;And our user name
FMSG <
> ;Another CRLF
MOVE A,QUEJFN ;Get file again
HRROI B,BUFFER ;Get buffer back
SETZ C, ;Until null
SOUT% ;Start making file
; Here with A/QUEJFN, add one recipient to the list in the file
NETRCP: MOVEI B,"L"-100 ;Control L
BOUT% ;To start another host/recip pair
HRROI A,BUFFER ;Get a place to buffer user name
HRROI B,1(ADR) ;With pointer from address block
CALL MOVSTR ;Copy string
MOVE A,QUEJFN ;Get JFN back again
HRROI B,1(B) ;With next string in block
SOUT% ;Send host name first
FMSG <
> ;Then a CRLF
HRROI B,BUFFER ;Then point to user name
SETZ C, ;To null
SOUT% ;Add user name
FMSG <
> ;Another CRLF to tie it off
RETSKP ;Done for now with the net send
; $SSTAT - Send a request for statistics to the send server
; call with D/PID, returns +1/always, D/updated PID
$SSTAT::SAVEAC <A,B,C,CX> ;Don't mung caller's registers
MOVE A,['SNDSTA'] ;SIXBIT function code
MOVEM A,BUFFER+SN$HDR ;Set it in IPCF page
SETZM BUFFER+SN$FLG ;No format flags
CALL DOIPCF ;Send it off
NOP ;Ignore failure
RET
; $WTRCP - Make string for recipient block
; Call with A/Destination pointer (string or JFN)
; B/Recipient block (as for $SEND)
; Returns +1/Always
$WTRCP::SAVEAC <B,C,ADR> ;Don't mung caller's registers
MKPTR (A) ;Make sure we have a real byte pointer
MOVE ADR,B ;Copy address block pointer
LOAD B,RC%TYP,(ADR) ;Find out what kind of send this is
JRST @[ WRTTTY ;RC.TTY - to line number
WRTUSR ;RC.USR - to user number
WRTALL ;RC.ALL - to all
WRTNET ](B) ;RC.NET - network send
WRTTTY: MOVE B,1(ADR) ;Get send data
MOVEI B,.TTDES(B) ;Turn into device designator
DEVST% ;Type it
IFNJE. <RET>
FMSG <Unknown terminal>
RET
WRTUSR: MOVE B,1(ADR) ;Get send data
DIRST% ;Type user name
IFNJE. <RET>
FMSG <Unknown user>
RET
WRTALL: FMSG <*> ;To everyone, just type a star
RET
WRTNET: HRROI B,1(ADR) ;Point to user
SETZ C, ;No limit
SOUT% ;Add it
HRROI C,1(B) ;Save it
MOVEI B,"@" ;Atsign
BOUT% ;Add that too
MOVE B,C ;Get pointer back
SETZ C, ;Ending on null
SOUT% ;Copy host name
RET
; Random string copying utilities
;MOVSTR - move ASCIZ string from source in B to dest in A, including the null
MOVSTR: MKPTR (A)
MKPTR (B)
DO.
ILDB C,B
IDPB C,A
JUMPN C,TOP.
ENDDO.
RET
; CPYSTR - copy an asciz string from source to destination without the null
CPYSTR: MKPTR (A)
MKPTR (B)
DO.
ILDB C,B
JUMPE C,R
IDPB C,A
LOOP.
ENDDO.
; .DIRST - Copy our user name or string describing n-l-i into pointer in A
.DIRST: SAVEAC <B,C,D> ;Don't mung other registers
PUSH P,A ;Save pointer
GJINF% ;Get our user number
HLRZ B,A ;Get left half only
CAIE B,500000 ;Look like a user number?
IFSKP.
MOVE B,A ;Save user number
POP P,A ;Get pointer back
DIRST% ;Type it out
IFSKP. <RET> ;If succeeded, we're all done
HRROI B,[ASCIZ/Unknown user, /] ;Else start making string
ELSE.
POP P,A ;Get dest back
HRROI B,[ASCIZ/Not logged in, /]
ENDIF.
CALL CPYSTR ;Start string
IFL. D ;If detached (how'd a n-l-i det run send???)
HRROI B,[ASCIZ/detached/]
JRST CPYSTR ;Say so
ENDIF.
MOVEI B,.TTDES(D) ;Else get as terminal designator
DEVST% ;Write "TTYn"
ERJMP .+1 ;Ignore errors
RET ;All done
END