Google
 

Trailing-Edge - PDP-10 Archives - BB-H348C-RM_1982 - swskit-v21/vax-mail/vmailr.mac
There are 5 other files named vmailr.mac in the archive. Click here to see a list.
;<STEVENS.VMAILR>VMAILR.MAC.67 24-Nov-81 10:28:00, Edit by STEVENS
; Corrected minor bug in GETFRM routine
;<STEVENS.VMAILR>VMAILR.MAC.66 24-Nov-81 08:31:00, Edit by STEVENS
; Corrected problem in skiping over personal name
;<STEVENS.VMAILR>VMAILR.MAC.65 23-Nov-81 10:10:00, Edit by STEVENS
; Ignore personal name in from field
; Scan to find subject field
;<STEVENS.VMAILR>VMAILR.MAC.64 20-Nov-81 09:29:00, Edit by STEVENS
; Cleaned up notification routine some more
;<STEVENS.VMAILR>VMAILR.MAC.63 20-Nov-81 08:58:00, Edit by STEVENS
; REPAIRED BUG IN NOTIFICATION OF FAILURE
;<STEVENS.VMAILR>VMAILR.MAC.62 20-Nov-81 08:40:00, Edit by STEVENS
; Disable Moby scan and clearing of decnet-flag bits
; This is to prevent conflict with DMAILR
;<LCAMPBELL.DECNET>DMAILR.MAC.190 26-May-81 18:00:00, Edit by LCAMPBELL
; Do physical-only open for SYSTEM:DECNET-MAILER.FLAGS
;<LCAMPBELL.DECNET>DMAILR.MAC.189 19-May-81 12:52:16, Edit by LCAMPBELL
;<LCAMPBELL.DECNET>DMAILR.MAC.188 19-May-81 12:49:07, Edit by LCAMPBELL
; Rip pass-through code out and put it in a separate module

	TITLE VMAILR - DECNET Mail User Process

	SUBTTL Larry Campbell

	SEARCH MACSYM,MONSYM,DNCUNV
	SALL
	NOSYM
	.DIRECTIVE FLBLST
	.REQUIRE SYS:MACREL,VNCONN
	EXTERNAL .DNINI,.DNCON		; Entry points in DNCONN

T1=1
T2=2
T3=3
T4=4
P1=5
P2=6
P3=7
P4=10
F=11
PTR=13				; global byte pointer to received mail
CNT=14				; global byte count for same
CX=16
P=17

.VER==5
.EDT==^D198

	LOC 137
	EXP <.VER>B11+.EDT
	RELOC
;MACROS

Define Clrbuf(Bufnam,Buflen),<
	Setzm Bufnam
	Move  T1,[Bufnam,,Bufnam+1]
	Blt   T1,Bufnam+Buflen-1
>

Define Nrecord(Buffer),<
	Move  T1,Njfn
	Hrroi T2,Buffer
	Movni T3,4
	Setz  T4,
	Sinr
	 Erjmp Fatal
>

Define Nsuccess,<
	Move  T1,Njfn
	Hrroi T2,[0]
	Movei T3,1
	Setz  T4,
	Soutr
>

Define Nsend(Record),<
	Move  T1,Njfn
	Hrroi T2,Record
	Setzb T3,T4
	Soutr
	 Erjmp Fatal
>

Define Find(String),<		;; Search for the given string
	Xlist
	Move T1,[Point 7,[Asciz/String/]]
	Call Findit		;; Call string compare routine
	List
>

DEFINE TMSG(STRING),<
	XLIST
	MOVE T1,LOGJFN
	HRROI T2,[ASCIZ \STRING\]
	SETZB T3,T4
	SOUT
	 ERJMP [HRROI T1,[ASCIZ \
?TMSG failure\]
		PSOUT
		HALTF]
	LIST
>

DEFINE YECCH(STRING),<
	XLIST
	ERJMP [	TCRLF
		TXNE F,F%WEEL
		CALL DTSTMP
		TMSG <?VMAILR: >
		MOVE T1,LOGJFN
		HRROI T2,[ASCIZ \STRING\]
		SETZB T3,T4
		SOUT
		TMSG < because: >
		MOVE  T1,LOGJFN
		HRLOI T2,.FHSLF
		SETZ  T3,
		ERSTR
		 JFCL
		 JFCL
		MOVE  T1,LOGJFN		;; insure log file gets written
		CLOSF			;;  ..
		 JFCL
		TXNN  F,F%WEEL		;;if SYSJOB, never stop
		HALTF
		JSP   CX,BEGIN ]
	LIST
>
DEFINE BLECH(STRING),<
	XLIST
	JRST [	TMSG <?VMAILR: Fatal internal error: >
		MOVE T1,LOGJFN
		HRROI T2,[ASCIZ \STRING\]
		SETZB T3,T4
		SOUT
		MOVE T1,LOGJFN	;;in case SOUT trashes T1 with error code
		CLOSF
		 JFCL
		TXNN F,F%WEEL	;; if SYSJOB, never stop
		HALTF
		JSP CX,BEGIN]
	LIST
>

DEFINE TCRLF,<TMSG <
>>

DEFINE HERALD(VER,EDT),<
	TMSG <VMAILR version VER(EDT) started
>>
;Flag bits

F%WEEL==1B0			; WHEEL
F%RNAM==1B1			; Rename required
F%PACK==1B2			; Postive acknowledgement received
F%ERRF==1B3			; Error message received
F%STAY==1B4			; "stay lit" flag for mailer flags bit

;Parameters

SLPTIM==^D3600000		;milliseconds to sleep between scans
MAXDIR==4000			;maximum number of dirs scannable
PDLLEN==200			;length of stack
FLGPAG==600			;page into which we map DECNET-MAILER.FLAGS
FLGADR==FLGPAG*1000		;address of DECNET-MAILER.FLAGS
NERMSG==50			;no. of words for error msg from 4n host
XSAGE==7,,0			;excessive age for queued mail (one week)
MOBYN==1,,0			;how often to do moby scans (once per day)
STRN==10000			;words of string space
HOSTNN==^D39			;maximum chars in hostname

;Storage

STACK:	BLOCK PDLLEN
LOGJFN:	BLOCK 1			;JFN on which to type most things
NODNAM:	BLOCK 5			;our node name
FLGJFN:	BLOCK 1			;JFN of PS:<SYSTEM>DECNET-MAILER.FLAGS
ERRMSG:	BLOCK NERMSG		;last fatal error message from other host
DIRS:	BLOCK MAXDIR		;list of directories to scan
LINBUF:	BLOCK ^D100		;line buffer for stuff from mail file
DEDHST:	BLOCK 100		;list of hosts known to be inaccessible or down
STRSP0:	BLOCK 1			;pointer to dead host name string space
STRSPC:	BLOCK STRN		;dead host name string space
MOBY:	BLOCK 1			;-1 => time for moby scan (ALL directories)

;STORAGE FOR VAX MESSAGE CHANGES

NJFN:	BLOCK 1			;Network JFN
MJFN:	BLOCK 1			;Mail file JFN
HOSTBA:	BLOCK 1			;Address of host TBLUK table
AROUTE:	BLOCK 1			;Pointer to routing string being used
BLNKBF:	ASCIZ / /		;Blank string for null records
BYTCNT:	BLOCK 1			;Lenght of message
TOOPTR:	BLOCK 1			;Pointer to To Buffer
TOOBUF:	BLOCK 1000		;To buffer
ATMBUF:	BLOCK 20		;Atom buffer
FRMBUF:	BLOCK 20		;From buffer
SUBBUF:	BLOCK 20		;Subject buffer
TEMP1:	BLOCK 20		;Temporary buffer
TEMP2:	BLOCK 20		;Temporary buffer
USER:	BLOCK 20		;User name or recipient buffer
HSTBUF:	BLOCK 20		;Host buffer
BIGBUF:	BLOCK 40000		;Storage for message file

LEVTAB:	PC1
	0
	0
CHNTAB:	1,,HICCUP		;net topology changed routine
	REPEAT ^D35,<EXP 0>
PC1:	BLOCK 1
SCNFLG:	BLOCK 1			;-1 => work in progress
INTRVL:	EXP SLPTIM		;sleep interval
SCNTOD:	BLOCK 1			;TOD (msec) of last scan
DNBLK:	BLOCK DN.INF+1		; Arg block for DNCONN utility
BEGIN:	RESET
	MOVE P,[IOWD PDLLEN,STACK]
	CLRBUF NODNAM,5		;clear node name, flag bits
	MOVEI T1,.PRIOU		;assume logging to TTY
	MOVEM T1,LOGJFN
	MOVEI T1,.FHSLF		;get our capabilities
	RPCAP
	MOVE T1,[SIXBIT /VMAILR/] ; assume nonprivileged name
	TXNE T3,SC%WHL!SC%OPR	; WHOPER?
	JRST [	MOVE T1,[SIXBIT /SDMALR/] ; yes, declare different name
		TXO F,F%WEEL		  ; remember that
		JRST .+1]
	MOVE T2,T1		; private name also
;	SETSN
;	 JFCL
	MOVX T1,.NDGLN		;function to get local node name
	MOVEI T2,T3		;arg block
	HRROI T3,NODNAM		;where to put node name
	NODE
	 YECCH <Impossible NODE failure>
	TXNE F,F%WEEL		; WHEEL or OPERATOR?
	JRST [	HERALD \.VER,\.EDT	; yes, announce our name and version
		CALL OPNLOG		; open log file
		MOVEM T1,LOGJFN
		CALL TOPLGY		; set up to interrupt on
					;  network topology change
		CALL DTSTMP		; start log file
		HERALD \.VER,\.EDT
		JRST .+1]
	MOVX T1,GJ%SHT!GJ%PHY	;find mailer flags, physical-only please
	HRROI T2,[ASCIZ /SYSTEM:DECNET-MAILER.FLAGS.1;P777777/]
	GTJFN
	 YECCH<Can't find SYSTEM:DECNET-MAILER.FLAGS.1>
	MOVX T2,<440000,,0>!OF%RD!OF%WR!OF%THW
	OPENF			;open thawed (so updates OK)
	 YECCH<Can't OPENF PS:<SYSTEM>DECNET-MAILER.FLAGS>
	MOVEM T1,FLGJFN		;remember handle
	HRLZ T1,T1		;from file page zero
	MOVE T2,[.FHSLF,,FLGPAG] ;to fork page FLGPAG
	MOVX T3,PM%RD!PM%WR	;read and write access
	PMAP			;get the page in
;	SETOM MOBY		;always do moby scan first time
	; ..
	; ..

BEGIN2:	SETOM SCNFLG		;flag scan in progress
	CALL SCANEM		;check for queued mail and process it
	TXNN F,F%WEEL		;if not wheel,
	JRST [	HALTF			;all done
		JSP CX,BEGIN]
	MOVE T1,LOGJFN		;close log file for readers
	CLOSF
	 JFCL
	CALL OPNLOG		;open it again
	MOVEM T1,LOGJFN		;save new JFN
	SETZM SCNFLG		;note that we're now idle
	MOVE T1,INTRVL		;how long to sleep before checks
BEGIN3:	DISMS
	TIME			;current TOD
	MOVE T3,SCNTOD		;get TOD of last scan
	SUB T1,T3		;difference
	CAML T1,INTRVL		;have we waited the full interval yet?
	JRST BEGIN2		;yes, go scan again
	MOVE T2,INTRVL
	SUB T2,T1		;how much longer to wait
	MOVE T1,T2		;be patient
	JRST BEGIN3
;Check for queued mail and handle (called also at net topology change)

SCANEM:	TIME			;get current TOD
	MOVEM T1,SCNTOD		;remember
	MOVEI T1,100		;empty dead host table
	MOVEM T1,DEDHST		;because we don't know anything yet
	MOVEI T1,STRSPC		;reset string space area
	MOVEM T1,STRSP0		; ..
	GTAD			;get current time
	MOVE T2,FLGADR+777	;and time of last moby scan
	SUB T1,T2		;compute difference
;	SKIPL T1		;if unreasonable,
;	CAML T1,[MOBYN]		;time for one yet?
;	SETOM MOBY		;yes
	CALL DIRLST		;build list of directories to scan
	JUMPE T1,R		;none, just return
	MOVN P1,T1		;save negative count
	TXNN F,F%WEEL		;if not WHEEL,
	JRST SCANM1		; skip the logging
	CALL DTSTMP		;time stamp the log file
	HRROI T3,[ASCIZ /----Beginning periodic scan
/]
	MOVEI T1,.FHSLF		;see if running as an interrupt routine
	RWM			; ..
	SKIPE T2		;if so, get different message
	HRROI T3,[ASCIZ /----Network topology changed, beginning scan
/]
	MOVE T2,T3		;put string pointer in right AC
	MOVE T1,LOGJFN		;write to the log file
	SETZB T3,T4
	SOUT
	SKIPN MOBY		;moby scan?
	JRST SCANM1		;no, skip this
	CALL DTSTMP
	HRROI T2,[ASCIZ /----Scanning all directories
/]
	SETZB T3,T4
	SOUT

SCANM1:	CLRBUF DNBLK,DN.INF+1	; Zero arg block
	MOVE T1,LOGJFN		; Where to type stuff
	MOVEM T1,DNBLK+DN.ERR
	MOVEM T1,DNBLK+DN.WRN
	MOVEM T1,DNBLK+DN.INF
	MOVEI T1,DNBLK		; Arg block address
	CALL .DNINI		; Init connect utility
	 JRST [	CALL DTSTMP		; Hmm, flag error
		TMSG <%Problem initializing routing database>
		JRST .+1]
	MOVEM T1,HOSTBA		;Save host table address
	HRLZ P1,P1		;make AOBJN pointer
SCANM2:	MOVE T1,DIRS(P1)	;get next directory number
	CALL CHKDIR		;check for queued mail, send if found
	AOBJN P1,SCANM2
	SETZM MOBY
	TXNN F,F%WEEL		;if not WHEEL,
	RET			; then all done
	CALL DTSTMP		; else time stamp log file
	TMSG <----End of scan
>
	RET
;Check directory whose number is in T1 for queued mail

CHKDIR:	ACVAR<IFN,JFN>		;indexable file handle,JFN
	TRVAR<<STRING,16>,DIRNUM> ;place to build string, dirnum
	TXZ F,F%STAY		;assume MAILER.FLAG bit won't stay lit
	MOVEM T1,DIRNUM		;preserve directory number

FILUP2:	HRROI T1,STRING		;where to build filespec string
	HRROI T2,[ASCIZ /PS:</]	;first part of filespec
	SETZB T3,T4
	SOUT			;start building filespec
	MOVE T2,DIRNUM		;get user number
	DIRST			;convert to string
	 JRST [	CAIN T1,DIRX2		; Insufficient system resources?
		TXO F,F%STAY		; Yes, don't flush this from queue
		JRST ALLDON]		; Wrap up
	HRROI T2,[ASCIZ />[--DECNET-MAIL--].*/]
	SETZB T3,T4		;finish off filespec string
	SOUT			; ..
	SETZ T2,		;insure ASCIZ
	IDPB T2,T1		; ..
	MOVE T1,[GJ%SHT+GJ%IFG+GJ%OLD+<0,,-3>] ;all generations
	HRROI T2,STRING		;point to filespec we built
	GTJFN			;get indexable file handle
	 ERJMP [TXNN F,F%RNAM		;any renames done?
		TXNE F,F%WEEL		; or doing this for system?
		JRST ALLDON		;yes, quit
		TMSG <%No queued DECNET mail>
		HALTF
		JSP CX,BEGIN]
	MOVE IFN,T1		;save indexable file handle
	CALL DTSTMP		;time stamp log file
	TMSG <Unspooling mail from >
	MOVE T1,LOGJFN		;where to put username
	MOVE T2,DIRNUM		;user number
	DIRST			;log it
	 YECCH<DIRST failure while logging>
	TCRLF
	MOVE T1,IFN		;get JFN of mail back
	JRST FILUP1		;go to it
FILOOP:	MOVE T1,IFN		;get indexable file handle
	GNJFN			;get next file
	 ERJMP ALLDON		;no more
FILUP1:	HRRZ JFN,T1		;isolate and preserve JFN
	HRRZS T1		;pass JFN only
	CALL SNDFIL		;send to appropriate host and delete
	 JRST [	MOVE T1,JFN
		TXO T1,CO%NRJ		;keep JFN lying around
		CLOSF
		 JFCL
		PUSH P,T1		;save offending JFN
		TCRLF
		TXNN F,F%RNAM		;need to be renamed?
		JRST [	TXO F,F%STAY		;no, keep flag lit for retries
			POP P,T1		;flush stack
			JRST FILOOP]		;check some more
		POP P,T1		;get JFN back
		CALL RNAMIT		;yes, rename to prevent retries
		RLJFN			;release JFN
		 YECCH<RLJFN failure after RNAMIT>
		JRST FILUP2]		;and check for more mail to send
	JRST FILOOP		;do for all files

;Let dmailr handle clearing the flag bits to prevent conflict

ALLDON:
;	MOVE T4,[ANDCAM T3,FLGADR(T1)] ; assume we'll be clearing the bit
;	TXNE F,F%STAY		;should flag bit stay lit 'cuz of err?
	TXNN F,F%STAY		;should flag bit stay lit 'cuz of err?
	RET			;return without changing flags
	MOVE T4,[IORM T3,FLGADR(T1)] ; yes, light it (in case not lit now)
	HRRZ T1,DIRNUM		;get directory number
	IDIVI T1,^D36		;get word number in DECNET-MAILER.FLAGS
	MOVSI T3,400000		;bit zero
	MOVN T2,T2		;negate bit number
	LSH T3,(T2)		;position bit correctly
	XCT T4			; light or clear it appropriately
	RET			;all done
;Send one file to appropriate host, JFN of file in T1
; P4 negative flags end of file
; Returns: +1: failure
;	   +2: success

SNDFIL:	ACVAR  <TOCNT>		; Count of the number of recipients
	STKVAR <ERRPTR,<HNAM,20>> ; Error msg ptr, mail JFN, net JFN, hostname
	HRRZM T1,MJFN		;save mail file JFN
	TXZ F,F%RNAM!F%ERRF!F%PACK	; No errors, no renames, no acks, yet
	CLRBUF ERRMSG,NERMSG	;zero error message save area
	HRROI T1,ERRMSG		;init pointer to error message string
	MOVEM T1,ERRPTR		; ..
	HRROI T1,HNAM		; Where to build hostname string

;Check to see if host is in the VAX router table.  If not, return and do
;nothing.  DMAILR will handle it.

	MOVE T2,MJFN		;mail file JFN
	MOVX T3,<1B11>		;type extension only
	SETZ T4,
	JFNS
	MOVE  T1,HOSTBA		;Is this host in the table?
	HRROI T2,HNAM
	TBLUK
	TXNN  T2,TL%EXM		;Skip if node is in routing table
	RET			;No, Must not be for a VAX let DMAILR handle it

	MOVE T1,MJFN		;mail file JFN
	MOVX T2,<070000,,0>+OF%RD ;open for ASCII read
	OPENF
	 ERJMP [TXNE F,F%WEEL
		CALL DTSTMP
		TMSG <%Can't open mail file
>
		RET]		;failure return
	CALL DTSTMP		;put date/time stamp in log file
	TMSG <Sending to >
	MOVE T1,LOGJFN		; Move hostname to log file
	HRROI T2,HNAM
	SETZB T3,T4
	SOUT
	TMSG <, >
	MOVE T1,MJFN		;mail file JFN
	CALL CHKOLD		;see if old and dusty yet
	 RET			;yes, don't bother with it
	MOVE T1,MJFN		;mail file JFN
	CALL HSTCHK		;host considered up?
	 JRST [	TMSG <known inaccessible, skipped.>
		RET]
	CLRBUF DNBLK,DN.INF+1	; Zero DNCONN arg block
	MOVE T1,LOGJFN		; Place all messages in log file
	MOVEM T1,DNBLK+DN.ERR
	MOVEM T1,DNBLK+DN.WRN
	MOVEM T1,DNBLK+DN.INF
	HRROI T1,HNAM		; Pointer to host name
	MOVEM T1,DNBLK+DN.HST
	MOVEI T1,^D27		; Object type 27 decimal
	MOVEM T1,DNBLK+DN.ROB
	SETZ T1,		; Assume defaults for flags
	TXNE F,F%WEEL		; Are we the system unspooler?
	TXO T1,DN%DTS!DN%SPL	; Yes, light time-stamp and spool flags
	MOVEM T1,DNBLK+DN.FLG	;  ..
	MOVEI T1,7		; Byte size
	MOVEM T1,DNBLK+DN.BSZ	;  ..
	MOVEI T1,DNBLK		; Pass arg block address
	CALL .DNCON		; Attempt the connect
	 JRST [	MOVE T1,MJFN		; Failed - mark host dead
		CALL HSTDED
		RET]		;  and give failure return
	MOVEM T1,NJFN		; Remember the JFN we just won
	MOVEI T2,2(T2)		; Point to routing string
	HRLI  T2,(POINT 7,,6)	; Form byte pointer to routing string
	MOVEM T2,AROUTE		; Save address of routing string
	SETZ P4,		; Success - clear end of file flag
;	JRST SNDFL2		; Go send the message
SNDFL2:
;
;PROGRAM FROM FOR SENDING DATA TO VAX
;
;STEP DESCRIPTION:
;	BEGIN SNDVAX
;	: EXTRACT FROM THE MAIL FILE WHO THE MAIL IS FROM
;	: ADD ROUTINE LIST TO STRING WHERE NEEDED
;	: SEND FROM STRING TO VAX *I/O*
;	: REPEAT UNTIL NO MORE RECIPIENTS
;	: : EXTRACT FROM THE MAIL FILE ONE OF THE RECIPIENTS
;	: : ADD TO LIST OF RECIPIENTS ALONG WITH NODE NAME
;	: : IF RECIPIENT IS ON NODE WERE SENDING TO
;	: : : SEND RECIPIENTS NAME TO NODE FOR ACKNOWLEDGEMENT
;	: : : RECEIVE ACKNOWLEDGEMENT FROM REMOTE NODE
;	: : : IF BAD ACKNOWLEDGEMENT
;	: : : : REPORT ERROR
;	: : : ENDIF
;	: : ENDIF
;	: END REPEAT
;	SEND NULL TO REMOTE HOST
;	SEND TO STRING CREATED DURING REPEAT LOOP
;	GET SUBJECT OF MESSAGE
;	SEND SUBJECT OF MESSAGE
;	SKIP 2 LINES IN MAILE FILE TO GET OVER THE GARBAGE
;	SEND THE TEXT OF THE MESSAGE TO THE REMOTE HOST IN LINE MODE
;	SEND A NULL TO THE REMOTE HOST
;	REPEAT UNTIL ONE ACK RECEIVED FOR EACH RECIPIENT
;	:  RECEIVE AN ACKNOWLEDGEMENT FROM THE REMOTE HOST
;	:  IF BAD ACKNOWLEDGEMENT
;	:  : GET ERROR MESSAGE FROM REMOTE HOST
;	:  : LOG ERROR MESSAGE INTO THE LOG FILE
;	:  ENDIF
;	END REPEAT
;

SNDVAX:	CLRBUF BIGBUF,40000	; CLEAR THE INPUT BUFFER

	MOVE  T1,MJFN		; READ 40000 CHARACTERS FROM
	HRROI T2,BIGBUF		; THE MAIL FILE
	MOVEI T3,40000
	SETZ  T4,
	SIN
	 ERJMP [MOVEI T1,.FHSLF		;this fork
		GETER			;get last error code
		HRRZS T2		; ..
		CAIE T2,IOX4		;end of file?
		JRST  [ MOVE  T1,ERRPTR		; BUILD MESSAGE TO USER
			HRROI T2,[ASCIZ\% I/O ERROR READING MAIL FILE: \]
			JRST  ESEND ]
		SETO P4,		;flag end of file
		MOVEI T1,12		;insure ends with line feed
		IDPB T1,T2		; ..
		JRST .+1]

	MOVN  CNT,T3		; CREATE THE COUNT OF THE NUMBER
	ADDI  CNT,40000		; OF BYTES READ
	MOVEM CNT,BYTCNT

	MOVE  PTR,[POINT 7,BIGBUF,6]	; CREATE POINTER TO INPUT BUFFER

	CALL  GETFRM		; GET WHO MAIL IS FROM
	 JRST [ MOVE  T1,ERRPTR		; BUILD MESSAGE TO USER
		HRROI T2,[ASCIZ\% ERROR PARSING FROM FIELD OF MESSAGE\]
		JRST  ESEND1 ]

	HRROI T1,NODNAM		; POINT TO OUR NODE NAME
	HRROI T2,HSTBUF		; HOST MESSAGE IS FROM
	STCMP			; IS MESSAGE FROM OUR HOST ?
	TXNN  T1,<SC%SUB>	; YES
	JRST  [ HRROI T1,HSTBUF		; GET TO END OF STRING
		HRROI T2,HSTBUF
		setzb t3,t4
		SIN
		BKJFN
		 JFCL
		HRROI T2,FRMBUF		; ADD ROUTE TO FRMBUF
		setzb t3,t4
		SOUT
		HRROI T1,FRMBUF
		HRROI T2,HSTBUF
		setzb t3,t4
		SOUT
		SETZM HSTBUF
		JRST  .+1 ]

	CALL  FIXHST		; DEVELOPE ROUTING STRING SO
				;  VAX CAN GET BACK TO US
	 JRST [ MOVE  T1,ERRPTR		; BUILD ERROR MESSAGE TO USER
		HRROI T2,[ASCIZ\% ERROR ENCOUNTERED IN ROUTING FILE\]
		JRST  ESEND1 ]

	NSEND <FRMBUF>		; SEND SENDER TO VAX W ROUTING

	MOVSI TOCNT,-^D100			; MAXIMUM OF 100 NAMES IN LIST
	SETZM TOOBUF
	MOVE  T1,[POINT 7,TOOBUF]
	MOVEM T1,TOOPTR		; SETUP POINTER TO TO BUFFER
SNDVX1:	FIND   <TO:>		; FIND "TO:" LIST
	 JRST [ CALL SKPLIN		; NOT ON THIS LINE, TRY NEXT
		 JRST [ MOVE  T1,ERRPTR		; NO TO FIELD FOUND, -ERROR-
			HRROI T2,[ASCIZ\% NO RECIPIENTS SPECIFIED\]
			JRST  ESEND1 ]
		JRST SNDVX1 ]		; GO TRY AGAIN
SNDVX2:	CALL  GETOCC		; PARSE TO FIELD AND BUILD TO STRING
	 JRST [ MOVE  T1,ERRPTR		; ERROR PARSING "TO" FIELD
		HRROI T2,[ASCIZ\% ERROR PARSING TO FIELD OF MAIL FILE\]
		JRST  ESEND1 ]
	JUMPE T1,SNDVX3		; DONE PROCESSING TO FIELD - LOOK FOR CC
	HRROI T1,HNAM		; POINT TO OUR NODE NAME
	HRROI T2,HSTBUF		; HOST MESSAGE IS FROM
	STCMP			; IS MESSAGE FROM OUR HOST ?
	TXNN  T1,<SC%SUB>	; YES
	JRST  SNDVX2		; NO, GET NEXT RECIPIENT
	NSEND <USER>		; SEND RECIPIENT TO VAX
	NRECORD <TEMP1>		; GET ACKNOWLEDGEMENT
	HLRZ  T1,TEMP1
	CAIE  T1,4000		; WAS IT GOOD ?
	 JRST [ TXO   F,F%ERRF		; SET FATAL ERROR FLAG
		JRST  SNDVER ]		; FETCH ERROR MESSAGE
	AOBJN TOCNT,SNDVX2		; LOOP TILL DONE
	JRST  [ MOVE  T1,ERRPTR		; TOO MANY RECIPIENTS
		HRROI T2,[ASCIZ\% TOO MANY RECIPIENTS.  PLEASE SPLIT MESSAGE\]
		JRST  ESEND1 ]

SNDVX3:	FIND   <CC:>		; FIND "CC:" LIST
	 JRST SNDVX5			; ABSENCE OF CC FIELD OK
SNDVX4:	CALL  GETOCC		; PARSE TO FIELD AND BUILD TO STRING
	 JRST [ MOVE  T1,ERRPTR		; ERROR PARSING "TO" FIELD
		HRROI T2,[ASCIZ\% ERROR PARSING TO FIELD OF MAIL FILE\]
		JRST  ESEND1 ]
	JUMPE T1,SNDVX5		; DONE PROCESSING TO FIELD - LOOK FOR CC
	HRROI T1,HNAM		; POINT TO OUR NODE NAME
	HRROI T2,HSTBUF		; HOST MESSAGE IS FROM
	STCMP			; IS MESSAGE FROM OUR HOST ?
	TXNN  T1,<SC%SUB>	; YES
	JRST  SNDVX4		; NO, GET NEXT RECIPIENT
	NSEND <USER>		; SEND RECIPIENT TO VAX
	NRECORD <TEMP1>		; GET ACKNOWLEDGEMENT
	HLRZ  T1,TEMP1
	CAIE  T1,4000		; WAS IT GOOD ?
	 JRST [ TXO   F,F%ERRF		; SET FATAL ERROR FLAG
		JRST  SNDVER ]		; FETCH ERROR MESSAGE
	AOBJN TOCNT,SNDVX4		; LOOP TILL DONE
	JRST  [ MOVE  T1,ERRPTR		; TOO MANY RECIPIENTS
		HRROI T2,[ASCIZ\% TOO MANY RECIPIENTS.  PLEASE SPLIT MESSAGE\]
		JRST  ESEND1 ]

SNDVX5:	NSUCCESS		; SEND NODE RECIPIENT LIST TERMINATOR
	NSEND <TOOBUF>		; SEND RECIPIENT LIST
	CALL  GETSUB		; GET SUBJECT FIELD
	 JRST [ MOVE  T1,ERRPTR		; ERROR PARSING SUBJECT FIELD
		HRROI T2,[ASCIZ\% ERROR PARSING SUBJECT FIELD IN MAIL FILE\]
		JRST  ESEND1 ]
	NSEND <SUBBUF>		; SEND SUBJECT FIELD
	JRST  SNDPA1

; NOW GET THE MESSAGE, ONE LINE AT A TIME

SNDPA0:	CALL SKPLIN		 ; SKIP TO NEXT LINE
	 JRST SNDONE		 ; NO MORE LINES, DONE!
SNDPA1:	CLRBUF ATMBUF,20
	MOVE T2,[POINT 7,ATMBUF] ; COPY REST OF THIS LINE INTO ATMBUF
SNDPA2:	CALL CPYLIN		 ; COPY LINE INTO ATMBUF
	JUMPE T1,[ SKIPE P4		; SKIP IF NOT EOF
		   JRST  SNDON1
		   PUSH  P,T2		; GET ANOTHER HUNK FROM THE MAIL FILE
		   MOVE  T1,MJFN
		   HRROI T2,BIGBUF
		   MOVEI T3,40000
		   SETZ  T4,
		   SIN
		    ERJMP [MOVEI T1,12		;insure ends with line feed
			   IDPB  T1,T2		; ..
			   MOVEI T1,.FHSLF	;this fork
			   GETER		;get last error code
			   HRRZS T2		; ..
			   CAIE T2,IOX4		;end of file?
			   JRST  [ POP   P,T2
				   MOVE  T1,ERRPTR	; BUILD MESSAGE TO USER
				   HRROI T2,[ASCIZ\% I/O ERROR READING MAIL FILE: \]
				   JRST  ESEND ]
			   SETO  P4,		;flag end of file
			   JRST  SNDPAX]
SNDPAX:		   POP   P,T2
		   MOVN  CNT,T3		; CREATE THE COUNT OF THE NUMBER
		   ADDI  CNT,40000	; OF BYTES READ
		   MOVEM CNT,BYTCNT
		   MOVE  PTR,[POINT 7,BIGBUF,6]	; CREATE POINTER TO INPUT BUFFER
		   JRST  SNDPA2 ]	; BACK FOR REST OF LINE

	SKIPN ATMBUF		 ; DON'T BOTHER WITH NULL RECORDS
	 JRST [ NSEND <BLNKBF>
		JRST SNDPA0]
	NSEND <ATMBUF>
	JRST SNDPA0

SNDONE:	SKIPE P4		; SKIP IF NOT EOF
	JRST  SNDON1
	MOVE  T1,MJFN		; GET ANOTHER BLOCK OF DATA FROM MAIL FILE
	HRROI T2,BIGBUF
	MOVEI T3,40000
	SETZ  T4,
	SIN
	 ERJMP [MOVEI T1,.FHSLF		;this fork
		GETER			;get last error code
		HRRZS T2		; ..
		CAIE T2,IOX4		;end of file?
		JRST  [ MOVE  T1,ERRPTR		; BUILD MESSAGE TO USER
			HRROI T2,[ASCIZ\% I/O ERROR READING MAIL FILE: \]
			JRST  ESEND ]
		SETO P4,		;flag end of file
		MOVEI T1,12		;insure ends with line feed
		IDPB T1,T2		; ..
		JRST .+1]
	MOVN  CNT,T3		; CREATE THE COUNT OF THE NUMBER
	ADDI  CNT,40000		; OF BYTES READ
	MOVEM CNT,BYTCNT
	MOVE  PTR,[POINT 7,BIGBUF,6] ; CREATE POINTER TO INPUT BUFFER
	JRST  SNDPA0		; BACK FOR REST OF LINE

SNDON1:	NSUCCESS

	HRLZS TOCNT		; CREATE AOBJN COUNT FOR NUMBER OF RECIPIENTS
	MOVNS TOCNT

SNDON2:	SETZM TEMP1		; GET RESPONSE
	MOVE  T1,NJFN
	HRROI T2,TEMP1
	MOVNI T3,4
	SETZ  T4,
	SINR
	 ERJMP [MOVEI T1,.FHSLF		; THIS FORK
		GETER			; GET LAST ERROR CODE
		HRRZS T2		;  ..
		CAIE  T2,IOX5		; DATA OR DEVICE ERROR??? !WHY!!!
		JRST  FATAL
		JRST  SNDON3 ]		; THINGS PROBABLY WENT OK
	HLRZ  T1,TEMP1
	CAIE  T1,4000		; WAS IT GOOD ?
	 CALL SNDVR1		; LOG ERROR AND CHECK FOR MORE ACKS
SNDON3:	AOBJN TOCNT,SNDON2	; LOOP UNILL ALL ACK's RECEIVED.
	TMSG  <SENT OK>
;	JRST  DONE		; ALL DONE!

DONE:	MOVE T1,NJFN		;get net JFN
	CALL CLZLNK		;close net link
	 JFCL		;*** temp until I figure out pass-through's weirdness
	TXNE F,F%ERRF		;if any errors occurred,
	JRST [	TXO F,F%RNAM		;remember to rename mail file
		RET]			;failure return
	MOVE T1,MJFN		;mail file JFN
	TXO T1,CO%NRJ		;don't release JFN
	CLOSF
	 ERJMP [TCRLF
		CALL DTSTMP
		TMSG <Can't close mail file>
		MOVE T1,MJFN
		RLJFN
		 JFCL
		RET]
	MOVE T1,MJFN
	TXO T1,DF%NRJ		;keep JFN around
	DELF			;delete the unsent mail file
	 ERJMP [TCRLF
		CALL DTSTMP
		TMSG <%Can't delete mail file>
		MOVE T1,MJFN
		RLJFN
		 JFCL
		RET]		;give failure return
	TMSG <, deleted.
>
	RETSKP

SNDVER:	CALL SNDVR1		; LOG ERROR
	JRST DONE		; ABORT

SNDVR1:	CLRBUF LINBUF,^D100	;zero out LINBUF
	MOVE   T1,NJFN		;net JFN
	HRROI  T2,LINBUF	;where to read stuff
	SETZB  T3,T4		;read what server has to say
	SINR			; ..
	 ERJMP [MOVEI T1,.FHSLF		;this fork
		GETER			;get last error code
		HRRZS T2		; ..
		CAIE T2,IOX4		;end of file?
		CAIN T2,IOX5		;*** temporary until I figure out
		SKIPA			;*** why PSTHRU always causes IOX5's
		JRST [	TCRLF
			CALL DTSTMP		;time stamp log file
			TMSG <%I/O error reading reply from mail server>
			POP  P,T1 		;throw away return
			JRST SNDERR]		;clean up and return bad
		SETO P4,		;flag end of file
		JRST .+1]		;rejoin main flow
	HLR   T1,LINBUF
	JUMPE T1,R		;END OF MESSAGE
	TXO F,F%ERRF		; error found, flag that
	TCRLF			;start message on new line
	CALL DTSTMP		;date-time stamp it
	MOVE T1,LOGJFN		;type it out
	HRROI T2,LINBUF
	SETZB T3,T4
	SOUT
	MOVE T1,ERRPTR		;also save in error message area
	HRROI T2,LINBUF
	SETZB T3,T4		; ..
	SOUT			; ..
	MOVEM T1,ERRPTR		;save current error message pointer
	JRST  SNDVER		;repeat until EOF

;FATAL ERROR OCCURED DURING TRANSMISSION OF MAIL

ESEND1:	SETZB T3,T4
	SOUT			; OUTPUT ERROR STRING
	JRST  ESEND2

ESEND:	SETZB T3,T4
	SOUT			; OUTPUT ERROR STRING
	BKJFN			; BACK UP POINTER OVER NULL
	 JFCL
	HRLOI T2,.FHSLF		; LAST ERROR, THIS PROCESS
	SETZ  T3,
	ERSTR
	 JFCL
	 JFCL
ESEND2:	TXO   F,F%ERRF		; SET FATAL ERROR FLAG
ESEND3:	TCRLF
	CALL  DTSTMP
	MOVE  T1,LOGJFN		; OUTPUT ERROR MESSAGE TO LOG FILE
	HRROI T2,ERRMSG
	SETZB T3,T4
	SOUT
	JRST  DONE

;FATAL NETWORK ERROR - MAIL REQUEUED

FATAL:	MOVE  T1,ERRPTR
	HRROI T2,[ASCIZ/% FATAL NETWORK ERROR: /]
	SETZB T3,T4
	SOUT
	BKJFN			;BACK UP POINTER OVER THE NULL
	 JFCL
	HRLOI T2,.FHSLF
	SETZ  T3,
	ERSTR
	 JFCL
	 JFCL
	TCRLF
	CALL  DTSTMP
	MOVE  T1,LOGJFN
	HRROI T2,ERRMSG
	SETZB T3,T4
	SOUT
SNDERR:	MOVE T1,NJFN		;get net JFN
	CALL CLZLNK		;close it
	 JFCL			;what can you do?
	RET			;failure return
;ROUTINE TO GET THE NAME OF WHO SENT THIS MAIL
;
;CALL:
;	PTR   = POINTER TO THE MAIL FILE
;	CALL GETFRM
;RETURNS:
;	FRMBUF= USER FROM WHO THE MAIL WAS FROM
;	HSTBUF= HOST NAME FROM WHICH THE MAIL WAS SENT

GETFRM:
	STKVAR <FCNT,FPTR>	; TEMPORARY POINT AND COUNT STORAGE
GTFRM1:	FIND   <FROM:>		; FIND SENDER
	 JRST [ CALL  SKPLIN		; NOT IN THIS LINE, TRY NEXT
		 RET			; OOPS... NO FROM
		JRST  GTFRM1 ]		; TRY NEXT LINE

	MOVEM CNT,FCNT		; SAVE COUNT
	MOVEM PTR,FPTR		;  AND POINTER
	LDB   T1,PTR		; GET A CHARACTER FROM MAIL FILE
GTFRM2:	CAIN  T1,"<"		; SCAN FOR REAL FROM FIELD
	JRST  GTFRM4		; REAL FIELD FOUND
	CAIN  T1,.CHCRT		; END OF LINE?
	JRST  GTFRM3		; YES, MUST HAVE BEEN REAL FIELD
	CALL  GETCHR		; GET NEXT CHARACTER
	 RET			; ERROR, TEXT EXHAUSTED
	JRST  GTFRM2

GTFRM3:	MOVE  CNT,FCNT		; RESTORE ORIGINAL COUNT
	MOVE  PTR,FPTR		; RESTORE ORIGINAL POINTER

GTFRM4:	CALL   GETCHR		; GOBBLE SPACE OR "<"
	 RET
	CLRBUF FRMBUF,20
	MOVE   T1,[POINT 7,FRMBUF]
	CALL   GETTOK		; GET SENDERS NAME
	 RET			; INVALID CHARACTER ENCOUNTERED
	CALL   SKPBLK		; SKIP WHITE SPACE
	 RET			; TEXT EXHAUSTED
	FIND   <AT>
	 RET			; NO AT ?
	CALL   GETNOD		; GET NODE SENT FROM
	 RET	
	CALL   SKPLIN		; SKIP TO NEXT LINE
	 RET			; TEXT EXHAUSTED
	RETSKP
;Routine to fix the host routing string so that VAX's can find the
;return path on reply.
;
;CALL:
;	AROUTE= STRING POINTER TO ROUTING STRING USED BY THE
;		ROUTER FOR THE CONNECTION
;	CALL FIXHST
;USED:
;	TEMP1 = TEMPORARY STORAGE FOR HOST NAME IN ROUTE
;	TEMP2 = TEMPORARY STORAGE FOR HOST NAME IN ROUTE
;RETURNS:
;	FRMBUF= WHO MESSAGE IS FROM WITH ROUTING AS REQUIRED

FIXHST:
	STKVAR <ARPTR>
	MOVE  T2,AROUTE			; GET STRING POINTER TO ROUTING STRING
	MOVE  T1,[POINT 7,TEMP1]	; GET PLACE TO STORE STRING
	CALL  GRTNOD			; GET NODE NAME
	 JRST RSKP			; NO ERROR, IMMEDIATE NEIGHBOR
FIXHS1:	MOVE  T1,[POINT 7,TEMP2]	; GET PLACE TO STORE NEXT NODE NAME
	CALL  GRTNOD			; GET NODE NAME
	 JRST R				; FATAL ERROR IN ROUTING TABLE
	LDB   T1,T2			; GET NEXT CHARACTER IN ROUTING TABLE
	SKIPN T1			; SKIP IF NOT ALL NODES READ
	 JRST FIXHS2			; ALL NODES READ, ROUTING COMPLETE
	MOVEM T2,ARPTR			; SAVE POINTER TO ROUTING STRING
	HRROI T1,TEMP1			; GET TO END OF STRING
	HRROI T2,TEMP1
	SETZB T3,T4
	SIN
	BKJFN
	 JFCL
	HRROI T2,HSTBUF			; TACK FIRST NODE READ ONTO BEGINNING
	SETZB T3,T4
	SOUT				;  OF HSTBUF AND PREPARE TO LOOP
	HRROI T1,HSTBUF
	HRROI T2,TEMP1
	SETZB T3,T4
	SOUT
	HRROI T1,TEMP1
	HRROI T2,TEMP2
	SETZB T3,T4
	SOUT
	MOVE  T2,ARPTR
	JRST  FIXHS1

FIXHS2:	HRROI T1,HSTBUF
	HRROI T2,HSTBUF
	SETZB T3,T4
	SIN
	BKJFN
	 JFCL
	HRROI T2,FRMBUF			; TACK ROUTING STRING ONTO BEGINNING
	SETZB T3,T4
	SOUT				; OF FRMBUF
	HRROI T1,FRMBUF
	HRROI T2,HSTBUF
	SETZB T3,T4
	SOUT
	RETSKP
;Routing to get routing node.
;Get a node name from the routing string being used.
;
;CALL:
;	T1    = POINTER TO ROUTING STRING
;	T2    = POINTER TO WHERE TO STORE NODE NAME
;	CALL GRTNOD
;RETURNS:
;	+1: ROUTING STRING EXHAUSTED
;	+2: OK, NODE RETURNED

GRTNOD:
	LDB  T3,T2		; GET A CHARACTER FROM ROUTING STRING
	CAIN T3,0		; SKIP IF STRING NOT EXHAUSTED
	JRST R
GRTND1:	IDPB T3,T1		; PUT CHARACTER IN OUTPUT STRING
	ILDB T3,T2		; GET CHARACTER FROM ROUTING STRING
	CAIN T3,0		; SKIP IF NOT END OF STRING
	JRST RSKP		; END OF STRING - RETURN SUCCESS
	CAIE T3,":"		; SKIP IF NOT A NODE SEPARATOR
	JRST GRTND1		; LOOP TILL DONE
	IDPB T3,T1		; PUT INTO OUTPUT STREAM
	ILDB T3,T2		; SHOULD BE FOLLOWED BY ANOTHER COLON
	CAIE T3,":"		;  CHECK FOR IT
	 RET			; SOMETHING IS WRONG
	IDPB T3,T1		; SAVE IN OUTPUT STRING
	IBP  ,T2		; POINT TO NEXT BYTE TO GET
	JRST RSKP		; NODE SEPARATOR - RETURN SUCCESS
;Routine to parse TO/CC field in the mail file and build the TO string.
;  Parses one user per call and returns the user and node. 
;
;CALL:
;	PTR    = POINTER TO THE MAIL FILE
;	TOOPTR = POINTER TO TOO BUFFER
;	CALL GETOCC
;VARIABLES RETURNED:
;	TOOBUF = STRING OF USERS MAIL ADDRESSED TO
;	HOST   = HOST USER IS TO RECEIVE MAIL ON
;	USER   = USER TO RECEIVE MAIL
;	TOOPTR = POINTER TO TOOBUF
;RETURNS:
;	+1: ERROR ENCOUNTERED IN MAIL FILE
;	+2: T1=0 LIST EXHAUSTED OR T1<>0 VALID VARIABLES RETURNED

GETOCC:
	CALL   SKPBLK		; SKIP OVER WHITE SPACE
	 RET				; TEXT EXHAUSTED
	LDB    T1,PTR		; GET CHARACTER FROM MAIL FILE
	CAIN   T1,.CHLFD	; IS CHARACTER A LINE FEED - END OF FIELD
	 JRST [ CALL SKPLIN		; YES, SKIP TO NEXT LINE
		 RET			; INPUT TEXT EXHAUSTED
		SETZ T1,		; NOTE END OF FIELD
		RETSKP ]		; RETURN SUCCESS
	CAIN   T1,";"		; IS CHARACTER AN ADDRESS LIST TERMINATOR ?
	 JRST [ CALL SKPLIN		; YES, SKIP TO NEXT LINE
		 RET			; INPUT TEXT EXHAUSTED
		SETZ T1,		; NOTE END OF FIELD
		RETSKP ]		; RETURN SUCCESS
	CAIN   T1,","		; IS CHARACTER A COMMA - MORE RECIPIENTS
	 JRST [ CALL  GETCHR		; FLUSH COMMA
		 RET			; TEXT EXHAUSTED
		CALL  SKPBLK		; SKIP TO START OF NEXT RECIPIENT
		 RET			; TEXT EXHAUSTED
		LDB   T1,PTR		; GET FIRST NON-BLANK CHARACTER
		CAIN  T1,.CHLFD		; END OF LINE ?
		 JRST [ CALL SKPLIN		; YES, LIST CONT'D ON NEXT LINE
			 RET			; TEXT GONE - ERROR
			CALL SKPBLK		; SKIP BLANKS
			 RET			; TEXT GONE - ERROR
			JRST GETOCC ]
		JRST  .+1 ]
	CLRBUF USER,20		; CLEAR USERNAME STORAGE AREA
	MOVE   T1,[POINT 7,USER] ; AND POINT TO IT
	CALL   GETTOK		; GET USER NAME SENDING TO
	 RET				; INVALID CHARACTER ENCOUNTERED
	CALL   SKPBLK		; SKIP WHITE SPACE
	 RET				; TEXT EXHAUSTED
	LDB    T1,PTR		; GET FIRST NON-BLANK CHARACTER
	CAIN   T1,":"		; LOGICAL NAME GARBAGE ?
	 JRST [ CALL GETCHR		; YES, THROW IT AWAY
		 RET			; ERROR - TEXT EXHAUSTED
		CALL SKPBLK		; SKIP WHITE SPACE
		 RET			; ERROR - TEXT EXHAUSTED
		JRST GETOCC ]
	FIND   <AT>
	 RET				; ERROR - MISSING NODE SPECIFICATION
	CLRBUF HSTBUF,20	; CLEAR HOST BUFFER
	CALL   GETNOD		; GET NODE SENT FROM
	 RET				; ERROR PARSING NODE NAME
	SKIPN  TOOBUF
	JRST   GTOCC1

	MOVEI  T1,","		; OUTPUT A COMMA
	IDPB   T1,TOOPTR
	MOVEI  T1," "		; FOLLOWED BY A SPACE
	IDPB   T1,TOOPTR

GTOCC1:	MOVE   T1,TOOPTR	; GET DESTINATION STRING POINTER
	HRROI  T2,HSTBUF	; OUTPUT HOST NAME TO TOBUF
	SOUT
	HRROI  T2,USER		; OUTPUT USER NAME TO TOBUF
	SOUT
	MOVEM  T1,TOOPTR	; SAVE UPDATED POINTER
	RETSKP
;Get the subject field and store it
;
;CALL:
;	PTR   = POINTER TO THE MAIL FILE
;	CALL GETSUB
;VARIABLES RETURNED:
;	SUBBUF= STRING CONTAINING THE SUBJECT OF THE MESSAGE
;RETURNS:
;	+1: ERROR ENCOUNTERED WHILE GETTING SUBJECT FIELD
;	+2: OK, SUBJECT FIELD IN SUBBUF

GETSUB:
	STKVAR <SCNT,SPTR>	; TEMPORARY STORAGE FOR COUNT AND POINTER
	MOVEM CNT,SCNT		; SAVE COUNT
	MOVEM PTR,SPTR		;  AND POINTER

GETSB1:	FIND <SUBJECT:>		; FIND SUBJECT FIELD
	 JRST [ CALL SKPLIN		; NOT IN THIS LINE, TRY NEXT
		JRST NOSUB		; NO SUBJECT, THAT'S OK
		JRST GETSB1 ]		; TRY NEXT LINE

	CALL SKPBLK		; SKIP WHITE SPACE
	 RET			; TEXT EXHAUSTED

	CLRBUF SUBBUF,20
	MOVE T2,[POINT 7,SUBBUF] ; COPY REST OF THIS LINE INTO SUBBUF
	CALL CPYLIN		 ;  ..
	CALL SKPLIN
	 RET			; TEXT EXHAUSTED
	RETSKP

NOSUB:	MOVE  CNT,SCNT		; RESTORE COUNT
	MOVE  PTR,SPTR		;  AND POINTER

	MOVE T1,BLNKBF
	MOVEM T1,SUBBUF		; PUT A BLANK STRING IN THERE
	 RETSKP
;Routine to get the node name from the mail file.
;
;CALL:
;	PTR   = POINTER TO MAIL FILE POSITIONED AT NODE NAME TO GET
;	CALL GETNOD
;VARIABLES RETURNED:
;	HSTBUF= NODE NAME WITH DOUBLE COLON TACKED ON THE END
;RETURNS:
;	+1: ERROR PARSING NODE NAME
;	+2: OK, NODE NAME IN HSTBUF

GETNOD:
	MOVE  T1,[POINT 7,HSTBUF] ; GET DESTINATION STRING POINTER
	CALL  GETTOK		; GET NODE NAME
	 RET				; ERROR ENCOUNTERED WHILE GETTING NODE
	MOVX  T2,":"		; GET A COLON
	IDPB  T2,T1		; PUT IT ON THE END OF THE NODE NAME
	IDPB  T2,T1
	SETZ  T2,		; ENSURE ASCIZ STRING
	IDPB  T2,T1
	RETSKP
;SKIP TO FIRST NONBLANK CHARACTER.
;SKIP OVER CNTRL-V'S, SPACES, AND CARRIAGE RETURNS.
;
;CALL:
;	PTR   = STRING POINTER TO TEXT THAT BLANKS ARE TO
;		BE SKIPPED IN
;	CALL SKPBLK
;RETURNS:
;	+1: TEXT EXHAUSTED
;	+2: OK, PTR POINTS AT FIRST NONBLANK CHARACTER

SKPBLK:	LDB  T1,PTR		; GET CHAR
	CAIN T1,""		; IGNORE CONTROL-V'S
	JRST SKPBL1
	CAIE T1,.CHCRT		; IGNORE RETURNS
	CAIN T1," "		;  AND BLANKS
	SKIPA
	RETSKP
SKPBL1:	CALL GETCHR		; SKIP TO NEXT
	 RET			; TEST GONE, ERROR
	JRST SKPBLK
;SKIP TO BEGINNING OF NEXT LINE.  SKIP OVER ALL CHARACTER ON A LINE
;UNTIL A CARRIAGE RETURN IS SEEN.
;
;CALL:
;	PTR   = STRING POINTER TO TEXT THAT A LINE IS
;		BE SKIPPED IN
;	CALL SKPLIN
;RETURNS:
;	+1: NO MORE TEXT LEFT
;	+2: OK, PTR POINTS TO BEGINNING OF LINE

SKPLIN:	LDB  T1,PTR		; GET NEXT CHAR
	CAIN T1,.CHLFD		; DID WE JUST EAT AN EOL?
	CALLRET GETCHR		; YES, SKIP OVER IT AND RETURN
	CALL GETCHR		; NO, EAT NEXT CHAR
	 RET			; TEXT EXHAUSTED
	JRST SKPLIN		; NO, EAT ANOTHER
;COPY A LINE OF TEXT FROM ONE AREA OF MEMORY TO ANOTHER.
;
;CALL:
;	T2    = STRING POINTER TO WHICH TEXT IS TO BE STORED
;	CALL CPYLIN
;RETURN:
;	+1: ALWAYS

CPYLIN:	LDB   T1,PTR		; GET A BYTE
CPYLN1:	JUMPE T1,R		; RETURN IF NULL FOUND
	CAIE  T1,15		; QUIT ON CR OR LF
	CAIN  T1,12
	JRST  R
	IDPB  T1,T2		; STUFF THIS ONE
	CALL  GETCHR		; FLUSH CHARACTER
	JRST  [ SETZ T1,	; ERROR - TEXT EXHAUSTED
		RET ]
	JRST  CPYLN1
;GET A CHARACTER
;
;CALL:
;	PTR   = STRING POINTER FROM WHICH A CHARACTER IS TO BE TAKEN
;	CALL GETCHR
;RETURNS
;	+1: NO MORE TEXT LEFT
;	+2: OK, CHARACTER GOTTEN IN T1

GETCHR:	JUMPE CNT,R		; ANY TEXT LEFT?
	ILDB  T1,PTR		; YES, SNARF CHAR
	SOJA  CNT,RSKP		; DECREMENT COUNT AND RETURN
;SEARCH FOR A STRING.  CALLED BY FIND MACRO
;
;CALL:
;	T1    = POINTER TO STRING TO FIND
;	CALL FINDIT
;RETURNS:
;	+1: STRING NOT FOUND, PTR AND CNT PRESERVED
;	+2: STRING FOUND, PTR AND CNT UPDATED TO POINT PAST STRING

FINDIT:	PUSH P,PTR		; SAVE CURRENT POINTER INFO
	PUSH P,CNT		; IN CASE STRING NOT FOUND
	MOVE P3,T1		; COPY T1 TO SAFE PLACE

FINDT1: LDB   T2,PTR		; FETCH A CHAR FROM SOURCE
	CAIL  T2,"a"		; IF LOWERCASE,
	CAILE T2,"z"		;  ..
	SKIPA			;  ..
	TRZ   T2,40		; THEN UPPERIZE IT
	ILDB  T3,P3		; FETCH CHAR FROM TEST STRING
	JUMPE T3,[ADJSP P,-2		; TEST STRING GONE, MATCH FOUND
		  RETSKP]		; FLUSH OLD POINTERS AND GIVE OK RETURN
	CAIL  T3,"a"		; UPPERIZE IT ALSO
	CAILE T3,"z"		;  ..
	SKIPA			;  ..
	TRZ   T3,40		;  ..
	CAME  T2,T3		; MATCHING SO FAR?
	JRST  FINDTX		; NO, QUIT NOW AND RESTORE POINTERS
	CALL  GETCHR		; SKIP TO NEXT CHAR IN MAIL
	 SKIPA			; NONE LEFT, FAIL
	JRST  FINDT1		; MORE TO LOOK AT, KEEP GOING

FINDTX:	POP P,CNT		; NO MATCH, RESTORE POINTERS
	POP P,PTR		;  AND GIVE BAD RETURN
	RET
;GET TOKEN - ALPHANUMERIC STRING - AND STORE IN ATMBUF
;
;CALL:
;	PTR   = STRING POINTER TO GET TOKEN FROM
;	T1    = STRING POINTER WHERE TOKEN IS TO BE STORED
;	CALL GETTOK
;VARIABLES RETURNED:
;	PTR   = UPDATED TO REFLECT TEXT TAKEN
;	T1    = UPDATED TO END OF TEXT INSERTED
;RETURNS:
;	+1: TEXT EXHAUSTED
;	+2: OK

GETTOK:	ACVAR <PTR1,CNT1>
	MOVE   PTR1,T1		; SAVE POINTER
	CALL   SKPBLK		; SKIP BLANKS
	 RET			; TEXT GONE, QUIT
	MOVEI CNT1,^D132	; MAX CHARS IN TOKEN

	LDB  T1,PTR		; SEE IF THIS USERNAME IS A QUOTED STRING
	CAIE T1,42		; DOES IT START WITH DOUBLE QUOTE?
	JRST GETTK2		; NO, DO ORDINARY THING

GETTK1: CALL GETCHR		; GET NEXT CHR
	 RET			; TEXT EXHAUSTED
	CAIE T1,42		; CLOSE QUOTE?
	JRST [  SOJLE CNT1,R		; NO, KEEP STORING IF ROOM LEFT
		IDPB T1,PTR1		; SAVE STRING WITH QUOTES REMOVED
		JRST GETTK1 ]		; ELSE JUST DROP CHARS ON FLOOR
	CALL GETCHR		; SKIP IT
	 RET			;  AND FALL THRU TO DO REST OF ADDRESS
	JRST GETTK3

GETTK2:	CALL  GTALPH		; GET AN UPPERCASE ALPHANUMERIC CHAR
	 RET
	JUMPE T1,GETTK3		; NONALPHANUMERIC
	IDPB  T1,PTR1		; STORE
	SOJG  CNT1,GETTK2	; GO FOR MORE
	RET			; ERROR - TOO MANY CHARACTERS

GETTK3:	MOVE T1,PTR1		; RETURN UPDATED POINTER IN T1
	CAIE CNT1,^D132		; DID WE FIND ANYTHING?
	RETSKP			; YES, EVERTHING'S COOL THEN
	LDB  T1,PTR		; NO, 1ST CHR OF NAME BAD -- RETRIEVE IT
GETTK4:	IDPB T1,PTR1		; SAVE BAD NAME FOR ERROR MESSAGE
GETTK5:	CALL GETCHR		; GET NEXT CHR OF BAD NAME
	 RET			; SKIP TO COMMA OR EOL THEN, THIS NAME IS BAD
	CAIE T1,","		;  ..
	CAIN T1,12		;  ..
	RET			; OK, GIVE BAD RETURN NOW
	SOJG CNT1,GETTK4	; BE CAREFUL NOT TO OVERFLOW ATOM BUFFER
	JRST GETTK5		; FULL, JUST TOSS CHARS INTO BIT BUCKET NOW
;GET ALPHNUMERIC CHARACTER.  CTRL-V AND DOT ARE CONSIDER ALPHANUMERIC.
;
;CALL:
;	PTR   = STRING POINTER TO GET ALPHANUMERIC CHARACTER FROM
;	CALL GTALPH
;RETURNS:
;	+1: TEXT EXHAUSTED
;	+2: T1=0 IF NEXT CHAR NO ALPHANUMERIC
;	    T1 CONTAINS CHAR IF ALPHANUMERIC

GTALPH:	LDB  T1,PTR		; SNIFF AT THIS CHAR
	CAIN T1,"-"		; ALLOW HYPHENS
	JRST GTALP1		;  ..
	CAIE T1,"."		; ALSO DOTS
	CAIN T1,""		;  AND CTRL-V'S
	JRST GTALP1		;  ..
	CAIL T1,"A"		; UPPERCASE ALPHABETIC?
	CAILE T1,"Z"		;  ..
	SKIPA			; NO, CHECK SOME MORE
	JRST GTALP1		; YES, PASS IT THRU
	CAIL T1,"a"		; LOWERCASE?
	CAILE T1,"z"		;  ..
	SKIPA			; NO, CHECK MORE CASES
	JRST [  TRZ T1,40		; YES, UPPERIZE IT
		JRST GTALP1]		;  AND PASS IT
	CAIL  T1,"0"		; DIGIT?
	CAILE T1,"9"		;  ..
	JRST [  SETZ T1,		; NO, INDICATE NONALPHANUMERIC
		RETSKP]
GTALP1:	PUSH P,T1		; SAVE THIS CHAR
	CALL GETCHR		; CHAR OK, SKIP TO NEXT
	 JFCL			; NEXT CALL WILL CATCH THIS
	POP  P,T1		; RETURN CHAR SKIPPED
	RETSKP
;Rename [--DECNET-MAIL--].host to ]--UNDELIVERABLE-DECNET-MAIL--[.host
; because of fatal error detected by server
; Call with JFN in T1

RNAMIT:	ACVAR <SJFN>		;source JFN
	STKVAR <<STR1,30>>	;where to build filespec string
	HRRZ SJFN,T1		;save JFN
	SETZM STR1		;clear string space
	HRLI T1,STR1		;zap from here
	HRRI T1,1+STR1		; to here
	BLT T1,27+STR1		; stop here
	HRROI T1,STR1		;where to build new filespec
	MOVE T2,SJFN		;JFN of bad mail
	MOVX T3,<1B2+1B5+JS%PAF> ;return and punctuate device and directory
	JFNS			; ..
	 YECCH<JFNS failure at RNAMIT>
	HRROI T2,[ASCIZ /]--UNDELIVERABLE-DECNET-MAIL--[./]
	SETZB T3,T4		;add filename and dot
	SOUT			; ..
	 YECCH<SOUT failure at RNAMIT>
	MOVE T2,SJFN		;now add original extension
	MOVX T3,<1B11>		; ..
	JFNS
	 YECCH<JFNS failure at RNAMIT 2>
	HRROI T2,[ASCIZ /.-1/]	;new generation
	SOUT
	MOVX T1,GJ%SHT		;get a JFN for the new filespec
	HRROI T2,STR1		;where the spec was built
	GTJFN
	 YECCH<GTJFN failure at RNAMIT>
	MOVE T2,T1		;new JFN
	MOVE T1,SJFN		;old JFN
	RNAMF			;rename it
	 YECCH<RNAMF failure at RNAMIT>
	MOVE SJFN,T2		;save new JFN
	MOVE T1,T2		;copy JFN
	TXO T1,CF%NUD+(.FBBYV)	;don't clank disk, word to change
	MOVSI T2,770000		;generation-retention-count field
	SETZ T3,		;zero (keep all generations)
	CHFDB			;do it
	MOVE T1,SJFN		;pass new JFN to NOTIFY
	CALL NOTIFY		;notify user of lossage
	MOVE T1,SJFN		;return new JFN
	RET
;Close net link, JFN in T1

CLZLNK:	STKVAR <NJF>
	MOVEM T1,NJF
	TXO T1,CZ%ABT		;Abort the link so program doesn't hang
	CLOSF
	 ERJMP CLZLN0
	RETSKP			;OK, that was easy
CLZLN0:	CAIN T1,DCNX11		;if error is "link aborted",
	JRST CLZLN1		; don't complain
	TCRLF
	CALL DTSTMP		;time stamp log file
	TMSG <%Close error for net link because:>
	MOVE T1,LOGJFN
	HRLOI T2,.FHSLF
	ERSTR
	 JFCL
	 JFCL
CLZLN1:	MOVE T1,NJF		;Try like hell to get rid of this JFN
	TXO T1,CZ%ABT		; ..
	CLOSF
	 JFCL
	RET
;Place date/time stamp in log file

DTSTMP:	TXNN F,F%WEEL		;only if system scanning
	RET
	MOVE T1,LOGJFN		;put into log file
	SETO T2,		;current date/time
	SETZ T3,		; everything
	ODTIM
	 JFCL
	TMSG < >		;delimit rest of line
	RET

;Open SYSTEM:VMAILR.LOG

OPNLOG:	MOVX T1,GJ%SHT
	HRROI T2,[ASCIZ /DECNET-LOG:VMAILR.LOG/]
	GTJFN			;try logical name first
	 ERCAL [MOVX T1,GJ%SHT
		HRROI T2,[ASCIZ /SYSTEM:VMAILR.LOG/]
		GTJFN
		 YECCH<Can't get JFN for log file>
		RET]
	MOVX T2,<070000,,0>!OF%RD!OF%WR!OF%APP
	OPENF			;open it
	 ERJMP [CAIN T1,OPNX9		;invalid simultaneous access?
		JRST [	TMSG <?LOG file already open, please DISABLE first.>
			HALTF
			JSP CX,BEGIN]
		TMSG <?Can't open log file because: >
		MOVX T1,.PRIOU
		HRLOI T2,.FHSLF		;type last error for this fork
		ERSTR
		 JFCL
		 JFCL
		HALTF
		JSP CX,BEGIN]
	HRRZ T1,T1		;return JFN only
	RET
;Build list of directories to scan, return how many in T1

DIRLST:	TXNE F,F%WEEL		;doing whole system?
	JRST DIRLS2		;yes, handle differently
	SETO T1,		;no, get our logged-in directory number
	MOVE T2,[-1,,P1]	;return result in P1
	MOVX T3,.JIUNO
	GETJI
	 YECCH<GETJI failure>
	MOVEM P1,DIRS		;one directory only (ours)
	MOVEI T1,1		; ..
	RET

DIRLS2:	MOVSI P1,-777		;words in DECNET-MAILER.FLAGS
	MOVSI P2,-MAXDIR	;words in directory list we build
	SKIPE MOBY		;doing moby scan?
	CALL LMOBY		;yes, set lots of bits

DIRLS3:	SKIPE T1,FLGADR(P1)	;any flags set in this word?
	JRST DIRLS4		;yes, examine it
DIRLS6:	AOBJN P1,DIRLS3		;no, check next word
	HRRZ T1,P2		;number of dirs to scan
	RET			;done

DIRLS4:	JFFO T1,.+2		;get bit number
	JRST DIRLS6		;no more bits in this word
	HRRZ T3,P1		;get word number
	IMULI T3,^D36		;times bits per word
	ADD T3,T2		;plus this bit position
	HRLI T3,500000		;plus magic number field
	MOVEM T3,DIRS(P2)	;save directory number
	MOVSI T3,400000		;bit zero
	MOVN T2,T2		;get negative bit position
	LSH T3,(T2)		;create bit we just handled
	TDZ T1,T3		;clear it
	AOBJN P2,DIRLS4		;move to next slot in directory list
	CALL DTSTMP		;stamp the log file
	TMSG <%Too many directories with queued mail, rebuild VMAILR with bigger MAXDIR
>
	HRRZ T1,P2		;number of dirs to scan
	RET			;quit now
;Set lots of bits in MAILER.FLAGS so race conditions don't rip us off

LMOBY:	ACVAR<USR>
	MOVX T1,RC%AWL
	HRROI T2,[ASCIZ /*/]
	RCUSR			;begin stepping through all user directories
	MOVE USR,T3

LMOBY1:	HRRZ T1,USR		;set this bit
	IDIVI T1,^D36		;in this word
	MOVX T3,1B0		;make a bit
	MOVN T2,T2		;negate shift amount
	LSH T3,(T2)		;position bit correctly
	IORM T3,FLGADR(T1)	;set it
	MOVX T1,RC%STP!RC%AWL
	HRROI T2,[ASCIZ /*/]
	MOVE T3,USR
	RCUSR			;step to next user
	TXNE T1,RC%NMD		;any more directories?
	JRST [	GTAD			;no, get current time
		MOVEM T1,FLGADR+777	;remember time we did this
		RET]
	MOVE USR,T3
	JRST LMOBY1
;Set up to interrupt on network topology change

   IFDEF TOPCHG,<
TOPLGY:	MOVX T1,.NDSIC		;function to set channel to interrupt on
	MOVEI T2,T3		; when net topology changes
	SETZ T3,		;interrupt on channel zero
	NODE			;do it
	 ERJMP [MOVE T1,INTRVL		;since we can't be topology-driven,
		LSH T1,-2		;quarter the sleep interval
		MOVEM T1,INTRVL		; ..
		RET]
	MOVEI T1,.FHSLF		;set up interrupt system
	MOVE T2,[LEVTAB,,CHNTAB]
	SIR
	EIR
	MOVX T2,1B0
	AIC
   >
   IFNDEF TOPCHG,<
TOPLGY:
   >
	RET			;all set!


;Here when net topology changes

HICCUP:	SKIPE SCNFLG		;is scan in progress?
	DEBRK			;yes, forget it then
	SETOM SCNFLG		;flag scan in progress
	MOVEI T1,^D5000		;wait 5 seconds for net to settle down
	DISMS
	CALL SCANEM		;do the heavy stuff
	MOVE T1,LOGJFN		;close log file for perusers
	CLOSF
	 JFCL
	CALL OPNLOG		;open it again
	MOVEM T1,LOGJFN		;save new JFN
	SETZM SCNFLG		;clear scan in progress flag
	DEBRK			;and return to background
;See if a host is up.
;Call:	T1/ JFN of mail file (extension is host name)
;	CALL HSTCHK
;Returns +1: host considered dead
;	 +2: host considerd up

HSTCHK:	STKVAR<<STRING,<<HOSTNN+5>/5>>>
	MOVE T2,T1		;put JFN in right AC
	HRROI T1,STRING		;where to put host name
	MOVX T3,<1B11>		;extension (host name) only
	JFNS
	MOVEI T1,DEDHST		;dead host table
	HRROI T2,STRING		;name of this host
	TBLUK			;is it known dead?
	TXNN T2,TL%EXM		;exact match for any name?
	RETSKP			;no, consider it up
	RET			;yes, consider it down


;Mark a host as dead.  Call with mail file JFN in T1.

HSTDED:	ACVAR<P1>
	MOVE P1,T1		;copy JFN
	MOVEI T1,<<HOSTNN+5>/5> ; room for a hostname and null
	CALL ALLSTR		;allocate string space
	 RET			;ignore failures
	MOVE T2,P1		;get JFN
	MOVE P1,T1		;save string address
	HRRO T1,T1		;form string pointer
	MOVX T3,<1B11>		;extension only
	JFNS
	MOVEI T1,DEDHST		;dead host table
	HRLZ T2,P1		;address of string
	TBADD			;add to table
	 ERJMP .+1		;ignore failures
	RET

;Allocate c(T1) words of storage
; Returns +1: failure
;	  +2: OK, address in T1

ALLSTR:	MOVE T2,STRSP0		;current free space
	ADDI T2,(T1)		; plus amount requested
	CAIL T2,STRSPC+STRN	;overflow?
	RET			;yes, fail
	MOVE T2,STRSP0		;no, get address of this string
	PUSH P,T2		;save for a bit
	SETZM (T2)		;zero it
	HRLZI T3,(T2)		;build BLT pointer
	HRRI T3,1(T2)		; ..
	ADDI T2,-1(T1)		;last word to zero
	BLT T3,(T2)
	ADDM T1,STRSP0		; ..
	POP P,T1		;return address of chunk
	RETSKP
;Check to see if queued mail too old to bother with
;Call:
;	T1/ JFN of queued mail
;Returns +1: too old, give up
;	 +2: OK

CHKOLD:	MOVE T2,[1,,.FBWRT]	;get last write date
	MOVEI T3,T4		; into T4
	GTFDB
	GTAD			;get current time/date
	SUB T1,T4		;compute age
	CAMG T1,[XSAGE]		;too old?
	RETSKP			;no, send it
	TCRLF			;new line
	CALL DTSTMP		;time-stamp log file
	TMSG <%Queued mail is too old -- renamed>
	TXNN F,F%WEEL		;system scanning?
	CALL [	TMSG < to ]--UNDELIVERABLE-DECNET-MAIL--[>
		RET]		;no, be wordier for lusers
	HRROI T1,ERRMSG		;no, build reason string
	HRROI T2,[ASCIZ /unsent mail is over one week old./]
	SETZB T3,T4
	SOUT
	TXO F,F%RNAM		; Remember to rename queued mail
	RET			; failure return
;Notify user of lossage reported by foreign host (eg., bad username)
; Cause of error is string stored in ERRMSG
; We will construct a mail file containing the reason and
; call SNDFIL to mail it to the sucker
;Call with:  JFN of [--UNDELIVERABLE-MAIL--] file in T1

NOTIFY:	TRVAR <UNDJFN,CPYJFN,OURDIR,<STRNG1,10>> ;undeliverable mail JFN, MAIL.CPY JFN, filename string
	TXNN F,F%WEEL		;only need to do this if WHEEL
	RET			;not WHEEL, user will get this typed
	MOVEM T1,UNDJFN		;save UNDELIVERABLE-MAIL JFN
	CALL DTSTMP		;log this notification
	TMSG <Notifying user of lossage
>
	SETO  T1,		;build filename string for notification file
	HRROI T2,OURDIR		; Results to OURDIR
	MOVEI T3,17
	GETJI
	 YECCH<GETJI failure>
	HRROI T1,STRNG1
	MOVE  T2,DIRNUM		; Get name of login directory
	DIRST
	 YECCH<DIRST failure while forwarding>
	HRROI T2,[ASCIZ /[--DECNET-MAIL--]./]
	SETZB T3,T4
	SOUT
	HRROI T2,NODNAM		;our node name (mailing to this node)
	SETZB T3,T4		; . .
	SOUT
	MOVX T1,GJ%SHT		;short form
	HRROI T2,STRNG1		;string we built
	GTJFN
	 YECCH<Can't GTJFN for MAIL.CPY>
	MOVX T2,<070000,,0>+OF%WR ;open for write, 7-bit bytes
	OPENF
	 YECCH<Can't OPENF MAIL.CPY>
	CALL BLDMSG		;build lossage message
	CLOSF
	 YECCH<Can't CLOSF MAIL.CPY>
	; ..
	; ..

	MOVE T4,[IORM T3,FLGADR(T1)] ; light it (in case not lit now)
	HRRZ T1,OURDIR		;get directory number
	IDIVI T1,^D36		;get word number in DECNET-MAILER.FLAGS
	MOVSI T3,400000		;bit zero
	MOVN T2,T2		;negate bit number
	LSH T3,(T2)		;position bit correctly
	XCT T4			; light or clear it appropriately
	RET
;Build message to notify user of lossage.  Write the message into
; the JFN in T1.

BLDMSG:	HRROI T2,[ASCIZ /Date: /]
	SETZB T3,T4
	SOUT			;start building text of mail
	SETO T2,
	MOVX T3,<OT%4YR!OT%SPA!OT%NSC!OT%NCO!OT%TMZ!OT%SCL> ; "12 Dec 1977 1906-PST"
	ODTIM
	 JFCL			;this can't happen
	HRROI T2,[ASCIZ /
From: DECNET mail process
To: /]				;more text
	SETZB T3,T4
	SOUT
	MOVE T2,UNDJFN		;get bad mail JFN
	MOVX T3,<1B5>		;output directory name only
	SETZ T4,
	JFNS
	HRROI T2,[ASCIZ / at /] ;delimit node name
	SETZB T3,T4		; ..
	SOUT
	HRROI T2,NODNAM		;our node name
	SETZB T3,T4		; ..
	SOUT
	HRROI T2,[ASCIZ /
Subject: Undeliverable mail

I'm sorry, but your mail to /]
	SETZB T3,T4		;more noise
	SOUT
	MOVE T2,UNDJFN
	MOVX T3,<1B11>		;type extension (host name)
	SETZ T4,
	JFNS
	HRROI T2,[ASCIZ /, which was queued for
transmission /]
	SETZB T3,T4
	SOUT
	PUSH P,T1		; Save notification JFN for a moment
	MOVE T1,UNDJFN		; JFN of queued mail
	MOVE T2,[1,,.FBWRT]	; Get last write date
	MOVEI T3,T2		; Into T2
	GTFDB			;  ..
	MOVX T3,<OT%4YR!OT%SPA!OT%NSC!OT%NCO!OT%TMZ!OT%SCL> ; "12 Dec 1977 1906-PST"
	POP P,T1		; Write date/time into message
	ODTIM
	 JFCL			;this can't happen
	HRROI T2,[ASCIZ /, encountered problems because:
/]
	SETZB T3,T4
	SOUT			;header now done
	HRROI T2,ERRMSG		;now type the error message
	SOUT
	HRROI T2,[ASCIZ /

You may use the REPAIR command in MS to correct the problem
and resubmit the mail.  If the problem was a user or users being
over quota, then all other users have received copies of the message.
Otherwise, nobody on the host named above has received the message.
   --------
/]
	SOUT
	RET			;return
;Table of reasons for disconnection from net link

REASON:	[ASCIZ /No special error/]			;0
	[ASCIZ /Resource allocation failure/]		;1
	[ASCIZ /Destination node does not exist/]	;2
	[ASCIZ /Node shutting down/]			;3
	[ASCIZ /Destination process does not exist/]	;4
	[ASCIZ /Invalid name field/]			;5
	[ASCIZ /Destination process queue overflow/]	;6
	[ASCIZ /Unspecified error/]			;7
	[ASCIZ /Third party aborted the logical link/]	;8
	[ASCIZ /User abort/]				;9
	FUNNY						;10
	[ASCIZ /Undefined error code/]			;11
	FUNNY						;12
	FUNNY						;13
	FUNNY						;14
	FUNNY						;15
	FUNNY						;16
	FUNNY						;17
	FUNNY						;18
	FUNNY						;19
	FUNNY						;20
	[ASCIZ /Connect initiate with illegal destination address/] ;21
	FUNNY						;22
	FUNNY						;23
	[ASCIZ /Flow control violation/]		;24
	FUNNY						;25
	FUNNY						;26
	FUNNY						;27
	FUNNY						;28
	FUNNY						;29
	FUNNY						;30
	FUNNY						;31
	[ASCIZ /Too many connections to node/]		;32
	[ASCIZ /Too many connections to destination process/] ;33
	[ASCIZ /Access not permitted/]			;34
	[ASCIZ /Logical link services mismatch/]	;35
	[ASCIZ /Invalid account/]			;36
	[ASCIZ /Segment size too small/]		;37
	[ASCIZ /Process aborted/]			;38
	[ASCIZ /No path to destination node/]		;39
	[ASCIZ /Link aborted due to data loss/]		;40
	[ASCIZ /Destination logical link address does not exist/] ;41
	[ASCIZ /Confirmation of disconnect initiate/]	;42
	[ASCIZ /Image data field too long/]		;43
NREASN==.-REASON

FUNNY:	ASCIZ /Unknown DECnet disconnect reason code/


	END BEGIN