Google
 

Trailing-Edge - PDP-10 Archives - bb-kl11c-bm_tops20_v6_1_atpch1_16 - autopatch/armail.c15
There are no other files named armail.c15 in the archive.
 REP 7/2	;15C1
		SEARCH MONSYM,MACSYM
 WIT
		SEARCH MONSYM,MACSYM, MSUNV
 REP 12/2	;15C2
		ARMEDT==VI%DEC+^D3	;EDIT LEVEL

 WIT
		ARMEDT==VI%DEC+^D5	;EDIT LEVEL

		F=0
 INS 19/2	;15C3
		Q2=6
		Q3=7
		P1=10
		P2=11
		P3=12
		P4=13
		P5=14
		P6=15
 INS 37/2	;15C4
		IPCPGS==10000		; Page to send to MX
 INS 7/3	;15C5
	IDNUM:	BLOCK	1		; ID number of current page to MX
	MSGNUM:	BLOCK	1		; Page number of message to MX
	MSGRCT:	BLOCK	1		; Number of records in current page to MX
	NUMRPT:	BLOCK	1		; Number of recipients on current line
	CURPTR:	BLOCK	1		; Pointer to the current line being formed
	CURPT2:	BLOCK	1		; Updated pointer to the current line
	USRNAM:	BLOCK	1		; Pointer to the current recipient name
	PAKSTS:	BLOCK	1		; Flag indicating if last page of message
	LCLRPT:	BLOCK	1		; Recipient is local
 REP 13/3	;15C6

	;End of variables to replace STKVARs
 WIT
	CURLIN:	BLOCK	^D40		; Current line being formed
	FILSPC:	BLOCK 	^D15		; File spec of message file
	NODNAM:	BLOCK	2		; ASCIZ name of our node
	NODPTR:	BLOCK	1		; Pointer to our node
 REP 26/3	;15C7
	MLRPID:	BLOCK 1			;PID OF [SYSTEM]MAILER OR -1 IF UNAVAILABLE
	SCNUD:	BLOCK 10		;TEMP AREA FOR USER NAME STRING
 WIT
	MYPID:	BLOCK 1			; PID obtained for talking with MX
	MLRPID:	BLOCK 1			;PID OF [SYSTEM]MAILER OR -1 IF UNAVAILABLE
	SAVAC:	BLOCK 20		; Save accumulator block
 DEL 1/10	;15C8

	; Routine to save and restore the AC's.

	SAVACS:	EXCH T1,0(P)		; Save T1, get return addr
		PUSH P,T2
		PUSH P,T3
		PUSH P,T4
		PUSH P,AP
		PUSH P,[SVACRT]		; Save return addr
		PUSH P,T1		; RETURN ADDR
		MOVE T1,-6(P)		; RESTORE T1
		RET			; "RETURN" TO CALLER
	SVACRT:	CAIA
		AOS -5(P)		; ROUTINE SKAP
		POP P,AP
		POP P,T4
		POP P,T3
		POP P,T2
		POP P,T1
		RET
 REP 5/11	;15C9
	;RETURNS +1: COULD NOT COMMUNICATE WITH [SYSTEM]MAILER
	;	 +2: MESSAGE SUCCESSFULLY PASSED TO MAILER (NOTE THAT THIS
	;	     ROUTINE DOESN'T CARE WHAT HAPPENS AFTER THE MESSAGE
	;	     HAS BEEN PUT IN MAILER'S HANDS)

	DECM:	SAVEAC <Q1>
	;	STKVAR <ARGPTR,<IPCFM,15>,<PDB,4>>
		MOVEM T1,ARGPTR		;SAVE ADDRESS OF ARGUMENT BLOCK
		SETZM CPYJFN		;NO JFN CURRENTLY ON MAIL.CPY
		SETZM .IPCFS+PDB	;SET NO PID OBTAINED FOR ME YET

	;SET UP PDB FOR SENDING MESSAGE TO [SYSTEM]MAILER

		CALL GTMLR		;GET MAILER'S PID
		 JRST DECMX1		;CAN'T, SO FAIL
		MOVEM T1,.IPCFR+PDB	;MAKE MAILER THE RECEIVER
		MOVX T1,IP%CPD		;REQUEST MONITOR TO CREATE A PID
		MOVEM T1,.IPCFL+PDB
		MOVEI T1,IPCFM		;GET ADDRESS OF IPCF MESSAGE
		MOVEM T1,.IPCFP+PDB	;(SIZE WILL BE FILLED IN LATER)

	;BUILD FILESPEC IN IPCFM FOR MAIL.CPY IN LOGGED-IN DIRECTORY

		SETO T1,		;THIS JOB
		HRROI T2,T4		;GET 1 WORD INTO T4
		MOVEI T3,.JILNO		;WANT LOGGED-IN DIRECTORY #
		GETJI			;GET IT
		 JRST DECMX1		;SHOULD NEVER FAIL
		MOVE T2,T4		;GET DIR #
		HRROI T1,IPCFM		;STRING GOES HERE
		DIRST			;CONVERT LOGGED-IN DIR # TO STRING
		 JRST DECMX1		;SHOULD NEVER FAIL
		HRROI T2,[ASCIZ/MAIL.CPY/]
		SETZ T3,
		SOUT			;APPEND NAME AND EXTENSION

	;OPEN MAIL.CPY

		GJINF			;GET CONNECTED DIRECTORY # IN T2
		SETZ T1,		;NO FLAGS
		DELDF			;EXPUNGE DELETED MAIL.CPY'S
		MOVX T1,GJ%SHT+GJ%FOU
		HRROI T2,IPCFM		;GET POINTER TO FILESPEC I JUST BUILT
		GTJFN			;GET JFN ON MAIL.CPY
		 JRST DECMX1		;FAILED
		MOVEM T1,CPYJFN		;REMEMBER JFN
		MOVE T2,[FLD(^D36,OF%BSZ)+OF%WR] ;BYTE SIZE, MODE
		OPENF			;OPEN FOR OUTPUT
		 JRST DECMX1		;FAILED
		SETZ T1,
		CALL CPY1		;NO FLAGS FOR MAILER

	;PARSE USER NAME STRING AND WRITE "TO" USER NUMBERS TO MAIL.CPY
 WIT
	;RETURNS +1: COULD NOT COMMUNICATE WITH MX
	;	 +2: MESSAGE SUCCESSFULLY PASSED TO MX (NOTE THAT THIS
	;	     ROUTINE DOESN'T CARE WHAT HAPPENS AFTER THE MESSAGE
	;	     HAS BEEN PUT IN MX'S HANDS)

	DECM:	MOVEM T1,ARGPTR		;SAVE ADDRESS OF ARGUMENT BLOCK
		SETZM CPYJFN		;No JFN currently on mail file
		SETZM MYPID		;SET NO PID OBTAINED FOR ME YET

	;SET UP PDB FOR SENDING MESSAGE TO MX

		CALL GTMLR		;GET MX'S PID
		 JRST DECMX1		;CAN'T, SO FAIL

		SETZM IDNUM		;No message ID at this point
		SETZM MSGNUM		;No message pages sent yet
		SETZM MSGRCT		;No records in message yet
		SETZM PAKSTS		;More pages to follow
		SETZM NUMRPT		;No recipients on current line

	;Open the mail file

		CALL OPNFIL
		JRST DECMX1		;Failed to open the file

	;Build date line and place in message file

		MOVEI T1,CURLIN		;Make a pointer to the current line
		HRLI T1,(POINT 7)	;This will be used alot so save it
		MOVEM T1,CURPTR		
		MOVEM T1,CURPT2		;Updated pointer, used in routine BLDRCP
		CALL BLDDAT

	;Build the sender record.

		CALL BLDSND

	;Build the recipient records
 REP 64/11	;15C10
		SETZ Q1,		;INITIALIZE COUNT OF USER NAMES
	DECM1:	CALL SCNU		;SCAN A USER NAME
		EXCH T1,T2		;GET USER # IN T1, STRING POINTER IN T2
		JUMPN T1,[CALL CPY1	;IF USER # OBTAINED, WRITE IT TO FILE
			AOJA Q1,.+1]	;COUNT VALID USER #
		MOVE T1,T2		;PREPARE FOR NEXT CALL TO SCNU
		CAIE T3,","		;COMMA AFTER USER NAME?
		CAIN T3," "		; OR BLANK?
		JRST DECM1		;YES, TRY FOR ANOTHER USER NAME
		JUMPE Q1,DECMX1		;END OF LIST, ERROR IF NO VALID NAMES
		SETZ T1,
		CALL CPY1		;TERMINATE "TO" LIST
		CALL CPY1		;NULL "CC" LIST

	;WRITE SUBJECT AND MESSAGE FIELDS TO MAIL.CPY

		SETZ T1,
		CALL CPYST		;INITIALIZE FOR COPYING STRINGS
		HRROI T1,[ASCIZ/SUBJECT: /]
		CALL CPYST		;WRITE NOISE
		MOVE Q1,ARGPTR		;GET ADDRESS OF ARGUMENT BLOCK
		MOVE T1,1(Q1)		;GET POINTER TO SUBJECT
		CALL CPYST		;OUTPUT SUBJECT FIELD
		HRROI T1,[ASCIZ/

	/]
		CALL CPYST		;OUTPUT CRLF CRLF
		MOVE T1,2(Q1)		;GET POINTER TO MESSAGE
		CALL CPYST		;OUTPUT MESSAGE
		MOVEI T1,1
		CALL CPYST		;FINISH UP PARTIAL WORD

	;CLOSE MAIL.CPY

		MOVE T1,CPYJFN		;GET JFN OF MAIL.CPY
		TXO T1,CO%NRJ		;KEEP JFN
		CLOSF			;CLOSE MAIL.CPY
		 JFCL

	;BUILD IPCF MESSAGE IN IPCFM CONTAINING FILESPEC OF MAIL.CPY
	;AND STORE LENGTH OF MESSAGE INTO PDB

		HRROI T1,IPCFM		;DESTINATION
		MOVE T2,CPYJFN		;MAIL.CPY JFN
		MOVE T3,[111110,,1]	;DEV,DIR,NAME,EXT,GEN,PUNCTUATE
		JFNS			;GET FILESPEC
		SETZ T2,
		IDPB T2,T1		;TIE IT OFF
		SUBI T1,-1+IPCFM	;GET # OF WORDS IN FILESPEC
		HRLM T1,.IPCFP+PDB	;STORE MESSAGE LENGTH INTO PDB

	;SEND MESSAGE OFF TO MAILER

		MOVEI T1,4		;PDB SIZE
		MOVEI T2,PDB		;PDB ADDRESS
		MSEND			;SEND MESSAGE TO MAILER
		 JRST DECMX1		;IT FAILED
		JRST DECMX2		;IT SUCCEEDED
 WIT
		MOVEM T1,USRNAM		;Save in case need to send another page
	RCPTLP:	CALL BLDRCP
		MOVE T1,USRNAM		;Pick up the status from BLDRCP
		CAMN T1,[-1]		;Any valid recipients found?
		JRST [ SKIPG IDNUM		;The first page of the message?
		       JRST DECMX1		;Yes, so really are no valid recipients
		       JRST SUBRE2]		;No, go build the sender record
		JUMPE T1,SUBREC		;No more recipients, build sender record
		CALL SNDMX		;Page is full, send off to MX
		JRST DECMX1		;An error occurred, quit
		JRST RCPTLP		;Get more recipients

	;Build the subject record. First make sure there is room

	SUBREC:	CAIG P3,BUFEND		;Still room?
		JRST SUBRE2		;Yes, build the subject record
		CALL SNDMX		;Page is full, send off to MX
		JRST DECMX1		;An error occurred, quit
	SUBRE2:	CALL BLDSUB		;Build the subject record

	;Build the message ID

		CALL BLDMID

	;Copy the text to the mail file and then close it

		CALL BLDTXT
		JRST DECMX1		;Could not close the mail file, quit

	;Build the file spec record last since MX returns an error if the file is
	;still open

		CAIG P3,BUFEND		;Still have room?
		JRST FSPREC		;Yes, build the file spec record
		CALL SNDMX		;Not enough room, send this page off
		JRST DECMX1		;An error occurred
	FSPREC:	CALL BLDSPC		;Build the file spec record
		
	;Send the last page of the message

		SETOM PAKSTS		;Indicate that this is the last page
		CALL SNDMX		;Send the last page off
		JRST DECMX1		;An error occurred, quit
		JRST DECMX2		;Success
 REP 134/11	;15C11
			 JFCL
 WIT
			 ERJMP .+1
 REP 139/11	;15C12
			 JFCL
			MOVE T1,CPYJFN	;GET JFN ONE MORE TIME
			RLJFN		;DISCARD IT
			 JFCL
			JRST .+1]
		SKIPE T1,.IPCFS+PDB	;DID I HAVE A PID?
 WIT
			 ERJMP .+1
			MOVE T1,CPYJFN	;GET JFN ONE MORE TIME
			RLJFN		;DISCARD IT
			 ERJMP .+1
			JRST .+1]
		SKIPE T1,MYPID		;DID I HAVE A PID?
 REP 2/12	;15C13
	;CPY1 - WRITE 1 WORD TO MAIL.CPY FILE
	; T1/ WORD TO BE WRITTEN
	;RETURNS +1: ALWAYS, ALL AC'S PRESERVED

	CPY1:	CALL SAVACS		;SAVE AC'S
		MOVE T4,T1		;COPY THE DATA TO BE WRITTEN
		MOVE T1,CPYJFN		;GET JFN ON FILE
		MOVE T2,[POINT 36,T4]	;GET POINTER TO DATA
		MOVNI T3,1		;WRITE 1 WORD
		SOUT			;WRITE TO FILE
		 ERJMP .+1
		RET


	;CPYST - WRITE ASCIZ STRING TO MAIL.CPY FILE
	;	   WE NEED THIS BECAUSE MAIL.CPY IS OPEN IN 36-BIT BYTE MODE
	; T1/ 0 TO INITIALIZE CPYST MEMORY, OR
	;     1 TO OUTPUT LAST PARTIAL WORD, OR
	;     STRING POINTER TO TEXT TO BE OUTPUT
	;RETURNS +1: ALWAYS

	CPYST:	JUMPE T1,[MOVE T1,[POINT 7,CPYSTD] ;INITIALIZATION CALL
			MOVEM T1,CPYSTP	;SET UP POINTER TO BUILDING AREA
			SETZM CPYSTD	;CLEAR BUILDING AREA
			RET]
		CAIN T1,1		;WRAP-UP CALL?
		JRST [	SKIPE T1,CPYSTD	;YES, DOES A PARTIAL WORD EXIST?
			CALL CPY1	;YES, OUTPUT IT
			RET]

	;T1/ POINTER TO STRING TO BE OUTPUT

		TLC T1,-1
		TLCN T1,-1		;OF FORM -1,,ADDR ?
		HRLI T1,(POINT 7)	;YES, CONVERT TO PDP-10 BYTE POINTER
		MOVE T3,T1		;MOVE POINTER OVER TO T3
	CPYST1:	ILDB T2,T3		;GET A CHARACTER FROM INPUT STRING
		JUMPE T2,R		;END OF STRING, RETURN
		IDPB T2,CPYSTP		;TRANSFER CHARACTER TO BUILDING AREA
		MOVE T2,CPYSTP
		TLNE T2,760000		;BUILDING AREA FULL?
		JRST CPYST1		;NO, PROCESS NEXT CHARACTER
		SOS CPYSTP		;YES, RESET POINTER TO BUILDING AREA
		MOVE T1,CPYSTD		;GET CONTENTS OF BUILDING AREA
		CALL CPY1		;WRITE BUILDING AREA TO FILE
		SETZM CPYSTD		;CLEAR IT FOR NEW DATA
		JRST CPYST1		;GET NEXT CHARACTER
	;GTMLR - GET MAILER'S PID
	;RETURNS +1: ERROR (E.G. PID NOT DEFINED)
	;	 +2: SUCCESS, T1/ MAILER'S PID

	GTMLR:
	;	STKVAR <<GTMPDB,4>,<GTMANS,2>>
		SKIPE T1,MLRPID		;FIRST TIME THROUGH?
		JRST [	CAMN T1,[-1]	;NO, WHAT DO I KNOW ABOUT MAILER?
			RET		;COULDN'T GET MAILER'S PID
			RETSKP]		;DID GET MAILER'S PID
		SETOM MLRPID		;SET MAILER'S PID CURRENTLY UNKNOWN

	;ASK <SYSTEM>INFO FOR MAILER'S PID
 WIT
	;GTMLR - GET MX'S PID
	;RETURNS +1: ERROR (E.G. PID NOT DEFINED)
	;	 +2: SUCCESS, T1/ MX'S PID

	GTMLR:

	;ASK <SYSTEM>INFO FOR MX'S PID
 REP 20/13	;15C14
		MOVE T1,[5,,[.IPCIW	;PACKET TO REQUEST PID FOR MAILER
			     0
			     ASCIZ/[SYSTEM]MAILER/]]
 WIT
		MOVE T1,[5,,[.IPCIW	;PACKET TO REQUEST PID FOR MX
			     0
			     ASCIZ/MXMAIL/]]
 REP 27/13	;15C15
		 JRST [	MOVE T1,.IPCFS+GTMPDB ;FAILED, GET CREATED PID
 WIT
		 JRST [	MOVE T1,.IPCFS+GTMPDB	;FAILED, GET CREATED PID
 REP 39/13	;15C16
		 JRST [	MOVE T1,.IPCFR+GTMPDB ;ERROR
			CALLRET RELPID]	;RELEASE PID AND FAIL
		MOVE T1,.IPCFR+GTMPDB	;GET MY PID
		CALL RELPID		;DON'T NEED IT ANY MORE
 WIT
		 JRST [	MOVE T1,.IPCFS+GTMPDB	 ;ERROR
			CALLRET RELPID]	;RELEASE PID AND FAIL
		MOVE T1,.IPCFR+GTMPDB	;GET MY PID
		MOVEM T1,MYPID		;Save for later
 REP 46/13	;15C17
		MOVE T1,.IPCFL+GTMPDB	;GET FLAGS WORD FROM PDB
		TRNE T1,IP%CFE		;ERROR?
		RET			;YES, FAIL
		MOVE T1,1+GTMANS	;GET PID OF INFO
		MOVEM T1,MLRPID		;REMEMBER IT FOR FUTURE REFERENCE
		RETSKP			;RETURN SUCCESS
	;SCNU - SCAN STRING FOR USER NAME
	; T1/ STRING POINTER TO USER NAME STRING
	;RETURNS +1: ALWAYS
	; T1/ BYTE POINTER TO CHARACTER FOLLOWING USER NAME
	; T2/ USER NUMBER OR 0 IF NO VALID USER NAME WAS FOUND
	; T3/ CHARACTER FOLLOWING USER NAME

	;NOTE:	THIS ROUTINE ASSUMES THAT USER NAMES CONTAIN ONLY UPPER CASE
	;	LETTERS, LOWER CASE LETTERS, DIGITS, AND PERIODS

	SCNU:
	;	STKVAR <<RDAT,3>>
		MOVEM T1,RDAT		;STORE CALLER'S STRING POINTER
		SETZM 1+RDAT		;CLEAR THE USER #
		MOVE T1,[POINT 7,SCNUD]	;SET UP POINTER TO TEMP AREA

	;SCAN STRING COPYING USER NAME INTO TEMP AREA (SCNUD) FOR RCUSR JSYS

	SCNU1:	ILDB T2,RDAT		;GET A CHARACTER FROM STRING
		IDPB T2,T1		;TRANSFER TO TEMP AREA
		CAIN T2,.CHCNV		;QUOTING CHARACTER?
		JRST [	ILDB T2,RDAT	;YES, GET CHARACTER FOLLOWING IT
			DPB T2,T1	;OVERWRITE QUOTING CHARACTER
			JRST SCNU1]	;CONTINUE
		CAIL T2,"a"		;LOWER CASE?
		CAILE T2,"z"
		SKIPA
		SUBI T2,40		;YES, CONVERT TO UPPER CASE
		CAIL T2,"A"		;UPPER CASE?
		CAILE T2,"Z"
		SKIPA
		JRST SCNU1		;YES, CONTINUE SCAN
		CAIL T2,"0"		;NUMERIC?
		CAILE T2,"9"
		SKIPA
		JRST SCNU1		;YES, CONTINUE SCAN
	;**; [5] AT SCNU1:+17L add 1 line	SM	15-Aug-85
		CAIE T2,"_"		;[5] UNDERSCORE?
		CAIN T2,"."		;PERIOD?
		JRST SCNU1		;YES, CONTINUE SCAN
		CAIE T2,"$"		;ALLOW DOLLAR SIGNS AND
		CAIN T2,"-"		; ALLOW DASHES
		JRST SCNU1		;VALID CHARACTER, CONTINUE SCAN

	;END OF USER NAME FOUND

		MOVEM T2,2+RDAT		;REMEMBER LAST CHARACTER FOR CALLER
		SETZ T2,
		DPB T2,T1		;TIE OFF USER NAME IN TEMP AREA
		MOVX T1,RC%EMO		;FLAGS (EXACT MATCH ONLY)
		HRROI T2,SCNUD		;GET POINTER TO TEMP AREA
		RCUSR			;CHECK OUT USER NAME
		 ERJMP SCNU2		;ERROR
		TXNN T1,RC%NOM		;VALID USER NAME?
		MOVEM T3,1+RDAT		;YES, RETURN USER # TO CALLER
	SCNU2:	DMOVE T1,RDAT		;LOAD UP AC'S TO RETURN TO CALLER
		MOVE T3,2+RDAT
 WIT
		MOVE T2,.IPCFL+GTMPDB	;GET FLAGS WORD FROM PDB
		TRNE T2,IP%CFE		;ERROR?
		RET			;YES, FAIL
		MOVE T1,1+GTMANS	;GET PID OF MX
		MOVEM T1,MLRPID		;REMEMBER IT FOR FUTURE REFERENCE
		RETSKP			;RETURN SUCCESS
	;Open the mail file. Save the file spec for the file spec record

	OPNFIL:	GJINF			;Get my user number
		MOVE T2,T1		;Place it where DIRST wants it
		HRROI T1,IPCFM		;Place my user name here
		DIRST			;Convert user number to user name
		RET			;Should never fail
		MOVEI T2,FILSPC		;Where to build the file spec
		HRLI T2,(POINT 7)	;Make it a pointer
		MOVE Q1,T2		;Save for the GTJFN
		MOVEI T4,[ASCIZ/POBOX:/] 
		HRLI T4,(POINT 7)	
	TRSSTR:	MOVEI P1,^D29		;Invariant byte number in file spec name
		ILDB T3,T4		;Transfer the structure name
		JUMPE T3,TRSDIR		;If finished, transfer the directory name
		IDPB T3,T2		;Into the file spec record
		JRST TRSSTR		;Get the next character
	TRSDIR:	MOVEI T3,"<"		;Get the directory name delimiter
		IDPB T3,T2		;Place in the file spec record
		MOVEI T4,IPCFM		;Address of user name
		HRLI T4,(POINT 7)	;Make into a pointer
	DIRREC:	ILDB T3,T4		;Get the next character
		CAIN T3,0		;End of the user name
		JRST FNDDIR		;Finish the directory name
		IDPB T3,T2		;Place in the file spec record
		AOS P1			;Increment the byte count
		JRST DIRREC		;Get the next character
	FNDDIR:	MOVEI T3,">"		;Get the directory delimiter
		IDPB T3,T2		;Place in the file spec record
		MOVEI T3,"M"		;Pick up first character of file name
		IDPB T3,T2		;Place in the file spec record
		MOVEI T3,"S"		;Pick up second character of file name
		IDPB T3,T2		;Place in the file spec record
	GETFS:	PUSH P,T2		;Save pointer in case file already exists
		GTAD			;Get a string
		AND T1,[070707,,070707]	;Make it SIXBIT numeric
		ROT T1,^D12		;Want the four that change most often
		MOVNI T3,4		;Need four digits
	GETFCH:	SETZ F,			;Clear out results from previous loop
		LSHC F,6		;Get the next SIXBIT character
		ADDI F,"0"		;Change to ASCII
		IDPB F,T2		;Place in the file spec record
		AOJN T3,GETFCH		;Convert any remaining
	TRSEXT:	MOVE T1,T2		;SOUT wants pointer in T1
		HRROI T2,[ASCIZ/.MAI.1;P770000/]
		SETZ T3,		;ASCIZ string
		SOUT			;Copy the extension to the file record
		ERJMP .+1		;Should never happen

		MOVX T1,GJ%SHT+GJ%NEW	;Must be a new file
		MOVE T2,Q1		;Point to the file spec
		GTJFN%			;Get its JFN
		ERJMP [POP P,T2			;Restore the pointer
	               CAIE T1,GJFX27		;Does file already exist?
		       RET			;No, must be another type of error
		       JRST GETFS]		;Yes, try another
		MOVEM T1,CPYJFN		;Save the JFN for later
		ADJSP P,-1		;Don't need the file spec pointer now
		       

	;Open the mail file

		MOVE T1,CPYJFN		;Pick up the JFN
		MOVE T2,[FLD(7,OF%BSZ)+OF%WR]
		OPENF			;OPEN FOR OUTPUT
		JRST [ MOVE T1,CPYJFN		;Error, so release the JFN
		       RLJFN
		       ERJMP .+1
		       RET]
		RETSKP			;Succeed

	;Build the date field and the first part of the from line.
	;Place in the message file

	BLDDAT:	HRROI T2,[ASCIZ/Date: /]
		SETZ	T3,		;Copy ASCIZ string
		SOUT			;Into the current line buffer
		ERJMP .+1		;Shouldn't happen
		SETO T2,		;Want the entire date
		MOVX T3,OT%4YR!OT%SPA!OT%NCO!OT%NSC!OT%SCL!OT%TMZ
		ODTIM%			;Get the formatted dat
		ERJMP .+1		;Shouldn't happen
		HRROI T2,[ASCIZ/
	From: /]
		SETZ T3,		;
		SOUT
		ERJMP .+1		;Shouldn't happen
		MOVE T1,CPYJFN		;Write out to the message file
		MOVE T2,CURPTR		;The current line
		SETZ T3,		;ASCIZ string
		SOUT			
		ERJMP .+1		;Shouldn't happen
 INS 2/15	;15C18
	;Build the sender record

	BLDSND:	MOVEI P3,.HDRSZ		;Number of bytes in message so far
		MOVEI P5,IPCPGS+.HDRSZ	;Address of sender record
		MOVEI T2,IPCFM		;Address of the sender name
		HRLI T2,(POINT 7)	;Make it into a pointer
		SETZ P1,		;No bytes in this record yet
		MOVE T3,P5		;Address of the current record
		ADDI T3,.RECTX		;Address of the sender name field
		HRLI T3,(POINT 7)	;Make into a pointer
		MOVE Q2,CURPTR		;Point to the current line buffer
	TRSSND:	ILDB T1,T2		;Get the next character of send name
		IDPB T1,T3		;Place into the sender record
		IDPB T1,Q2		;Place in the current line buffer
		AOS P1			;Increment the byte count
		CAIE T1,0		;Finished?
		JRST TRSSND		;No, get the next character

	;Finish up the sender record

		AOS T1,MSGRCT		;Increment the record count
		MOVEM T1,.RECNM(P5)	;Place in the sender record
		MOVEI T1,.SENDR		;Record type
		MOVEM T1,.RECTY(P5)	;Place in the sender record
		IDIVI P1,5		;Number of words in this record
		SKIPE P2		;A partial word?
		AOS P1			;Yes, count as a full word
		ADDI P1,.RECHS		;Include the header size
		MOVEM P1,.RECLN(P5)	;Place in the record
		ADD P3,P1		;Add record size to message size
		ADD P5,P1		;Address of the next record

	;Pick up the node name and append to sender's name

		MOVEI T1,.NDGLN		;Want our node name
		MOVEI P1,NODNAM		;Where to place it
		HRLI P1,(POINT 7)	;Make into a pointer
		MOVEM P1,NODPTR		;Will need it again
		MOVEI T2,P1		;Address of the argument block
		NODE			;Get our node name
		ERJMP [ SETZM NODNAM		;No node name
			JRST CPYFRM ]		;Copy From: string
		MOVEI T1,"@"		;Pick up an at sign
		DPB T1,Q2		;Overwrite the zero
		MOVE T1,NODPTR		;Point to node name
	MOVNOD:	ILDB T2,T1		;Get the next character
		IDPB T2,Q2		;Place in the current buffer
		CAIE T2,0		;Finished?
		JRST MOVNOD		;No, continue

	;Copy the From: string to the mail file

	CPYFRM:	MOVE T1,CPYJFN		;JFN of the mail file
		MOVE T2,CURPTR		;The string to be written
		SETZ T3,		;ASCIZ string
		SOUT			;Copy the from string to the mail file
		ERJMP .+1		;Should not happen
		MOVE T1,CPYJFN		
		HRROI T2,[ASCIZ/
	To: /]
		SETZ T3,		;ASCIZ string
		SOUT			;Copy to the mail file
		ERJMP .+1		;Should not happen
		RET
	;Build the recipient records
	;P3 contains the global message word count 
	;P5 address of current record

	BLDRCP:	MOVE Q1,CURPT2		;Point to the start of the current line
		MOVE Q2,USRNAM		;Point to current recipient name
		MOVE Q3,NUMRPT		;No recipients in current line
		MOVEI P4,","		;For convience		
	NXTRCD:	SETZ P1,		;No bytes in this record yet
		SETZM LCLRPT		;Assume local
		MOVE T4,P5		;Address of the current record
		ADDI T4,.RECTX		;Address of recipient field
		HRLI T4,(POINT 7)	;Make into a pointer
		MOVE P6,Q1		;Save position in case recipient is invalid
	NXTCHR:	ILDB T2,Q2		;Get the next character of recipient name
		CAIN T2,.CHCNV		;A ^V?
		JRST [ ILDB T2,Q2		;Yes, so get the following character
		       JRST DEPCHR]		;And deposit it
		CAIL T2,"a"		;LOWER CASE?
		CAILE T2,"z"
		SKIPA
		JRST DEPCHR		;Lower case, so deposit it
		CAIL T2,"A"		;UPPER CASE?
		CAILE T2,"Z"
		SKIPA
		JRST DEPCHR		;Yes, so deposit it
		CAIL T2,"0"		;NUMERIC?
		CAILE T2,"9"
		SKIPA
		JRST DEPCHR		;Yes, so deposit it
		CAIE T2,"_"		;UNDERSCORE?
		CAIN T2,"."		;PERIOD?
		JRST DEPCHR		;Yes, so deposit it
		CAIE T2,"$"		;ALLOW DOLLAR SIGNS AND
		CAIN T2,"-"		; ALLOW DASHES
		SKIPA			;Deposit this character
		JRST ENDNAM		;End of the recipient name found
	DEPCHR:	IDPB T2,T4		;Place character into recipient record
		IDPB T2,Q1		;Place character into current line buffer
		AOS P1			;Increment the byte count
		JRST NXTCHR		;Pick up the next character

	;The end of a recipient name has been found
	;First check if it is valid

	ENDNAM:	SKIPN P1		;Was there a recipient?
		JRST [ CAIE T2," "		;No, Another potential recipient?
		       CAIN T2,","
		       JRST NXTCHR		;Yes, check it out
		       MOVE Q1,P6		;Reset the pointer
		       JRST LSTRCP]		;No, finished
		CAIE T2,"@"		;A node name follows?
		JRST CHKLCL		;No, check if local
		AOS LCLRPT		;Increment the number of @'s found
		JRST DEPCHR		;Pick up the node name
	CHKLCL:	PUSH P,T2		;Save the terminating character
		SKIPN T1,LCLRPT		;Local recipient?
		JRST LCLNAM		;Yes, validate the recipient
		CAIE T1,1		;Valid node name string?
		JRST INVUSR		;No, reject this recipient
		SETZ T2,		;Make the recipient name ASCIZ
		IDPB T2,T4		;In the recipient record
		IDPB T2,Q1		;VALUSR expects this
		AOS P1			;Increment the record byte count
		JRST VALUSR		;Complete the recipient record
	LCLNAM:	SETZ T2,		;Make the record ASCIZ
		IDPB T2,T4
		IDPB T2,Q1		;RCUSR needs the string to be ASCIZ
		AOS P1			;Include in the byte count
		MOVX T1,RC%EMO		;Want an exact match
		MOVE T2,P6		;One byte before the recipient name
		RCUSR
		ERJMP INVUSR		;Assume invalid
		TXNN T1,RC%NOM		;Valid user name?
		JRST CHKNDEF		;Yes, add node name to user name

	;An invalid user. Reset the pointers and the byte count

	INVUSR:	POP P,T2		;Pick up the termination character
		CAIE T2," "		;Perhaps more recipients?
		CAIN T2,","
		SKIPA			;Yes, check it out
		JRST LSTRCP		;No, finish up
		MOVE Q1,P6		;Restore the pointer to where it was
		JRST NXTRCD

	;Add a node name, if there is one

	CHKNDE:	SKIPN NODNAM		;Is there a node name?
		JRST VALUSR		;No, so complete the recipient record
		MOVEI T2,"@"		;Pick up an AT sign
		DPB T2,Q1		;Place in the current buffer
		MOVE T1,NODPTR		;Get pointer to the ASCIZ node name
	NXTNCH:	ILDB T2,T1		;Get the next node name character
		IDPB T2,Q1		;Place in the current buffer
		CAIE T2,0		;Finished?
		JRST NXTNCH		;No, get the next character

	;A valid user has been found. First complete the current recipient record.

	VALUSR:	AOS T1,MSGRCT		;Increment the record count
		MOVEM T1,.RECNM(P5)	;Place in the record
		MOVEI T1,.DESTN		;Type of record is recipient (destination)
		MOVEM T1,.RECTYP(P5)	;Place in the record
		IDIVI P1,5		;Find the number of words in name
		SKIPE P2		;A partial word?
		AOS P1			;Yes, count as a whole word
		ADDI P1,.RECHS		;Include the header size
		MOVEM P1,.RECLN(P5)	;Place length into the record
		
	;Check if the current line should be written to the mail file

		MOVE AP,Q1		;Remember position before last comma
		DPB P4,Q1		;Place a comma after the name
		MOVEI T1," "		;Append a blank
		IDPB T1,Q1		;To the current line
		AOS Q3			;Increment the recipient count
		CAIE Q3,3		;Need a new line?
		JRST CHKLST		;No, check if this is the last recipient
		MOVEI T1,15		;Pick up a carriage return
		DPB T1,Q1		;Overwrite the null
		MOVEI T1,12		;Pick up a line feed
		IDPB T1,Q1		;Place in the current line buffer
		MOVEI T1," "		;Add blanks to the start of the new line
		MOVNI T2,4		;Add four blanks
	ADDBLK:	IDPB T1,Q1		;Add the next blank
		AOJN T2,ADDBLK		;Do the next
		SETZ T1,		;Make it ASCIZ
		IDPB T1,Q1
		MOVE T1,CPYJFN		;Write to the mail file
		MOVE T2,CURPTR		;Point to the current line
		SETZ T3,		;ASCIZ string
		SOUT			
		ERJMP .+1		;Should never happen
		SETZ Q3,		;Reset current line count
		MOVE Q1,CURPTR		;Reset pointer to start of current line

	;Check if last recipient

	CHKLST:	ADD P3,P1		;Update the message size	
		ADD P5,P1		;Point to the next record
		POP P,T1		;Get back the terminating character
		CAIE T1," "		;If blank, there may be more
		CAIN T1,","		;IF comma, there may be more
		SKIPA
		JRST LSTRCP		;The last recipient has been found

	;There may be more recipients. Make sure there's still space in this
	;message page.

		CAILE P3,BUFEND		;Still room?
		JRST [ MOVEM Q2,USRNAM		;Update user pointer
		       MOVEM Q1,CURPT2		;Update current line pointer
		       MOVEM Q3,NUMRPT		;Number of recipients on this line
		       RET]			;Go send off this page to MX
		JRST NXTRCD		;Form the next record

	;The last recipient has been found. Make sure there was at least one
	;valid recipient

	LSTRCP:	SETOM USRNAM		;Assume no valid users
		MOVE T1,MSGRCT		;Get the record count
		SKIPE IDNUM		;First time through?
		AOS T1			;No, so no sender record in record count
		CAIG T1,1		;More than just the sender record?
		RET			;No, then no valid users
		SETZM USRNAM		;Yes, indicate so
		MOVE T1,CURPTR		;Start of the current line
		CAMN T1,Q1		;Same as the updated pointer?
		JRST OVWCOM		;Yes, overwrite final comma in the file
		MOVEI T1,15		;Overwrite the final comma
		DPB T1,AP		;Making the string ASCIZ
		MOVEI T1,12		;Add a line feed
		IDPB T1,AP		;Place as the last character
		SETZ T1,		;Make it ASCIZ
		IDPB T1,AP
		MOVE T1,CPYJFN		;Write final line out to the mail file
		MOVE T2,CURPTR		;Point to the start of the line
		SETZ T3,		;ASCIZ string
		SOUT
		ERJMP .+1		;Should not happen
		RET

	OVWCOM:	MOVE T1,CPYJFN		;Pick up the message file JFN
		RFPTR			;Find pointer of the file
		ERJMP .+1		;Should not happen
		SUBI T2,7		;Back up to the last comma
		SFPTR			;Position the pointer there
		ERJMP .+1		;Should not happen
		HRROI T2,[ASCIZ/ 
	/]
		SETZ T3,		;ASCIZ string
		SOUT			;Write out to the file
		ERJMP .+1		;Should not happen
		RET
	;Build the subject record.

	BLDSUB:	MOVE Q1,ARGPTR		;Get the address of the argument block
		MOVE T2,1(Q1)		;Get the pointer to the subject line
		TLC T2,-1
		TLCN T2,-1		;OF FORM -1,,ADDR ?
		HRLI T2,(POINT 7)	;YES, CONVERT TO PDP-10 BYTE POINTER
		MOVE Q2,T2		;Save a copy for the mail file
		SETZ P1,		;No bytes in this record yet
		MOVE T3,P5		;Address of this record
		ADDI T3,.RECTX		;Address of the subject field
		HRLI T3,(POINT 7)	;Make it into a pointer
	TRSSUB:	ILDB T1,T2		;Get the next character of the subject
		IDPB T1,T3		;Place in the subject record
		AOS P1			;Increment the byte count
		CAIE T1,0		;Finished?
		JRST TRSSUB		;No, continue transferring

	;Finish the subject record

		AOS T1,MSGRCT		;Increment the record count
		MOVEM T1,.RECNM(P5)	;Place in the subject record
		MOVEI T1,.SJSTR		;Get the record type
		MOVEM T1,.RECTY(P5)	;Place in the record
		IDIVI P1,5		;Get the number of words
		SKIPE P2		;A partial word?
		AOS P1			;Yes, count as a full word
		ADDI P1,.RECHS		;Include the header size
		MOVEM P1,.RECLN(P5)	;Place in the record
		ADD P3,P1		;Total byte count of message so far
		ADD P5,P1		;Address of the next message

	;Copy the subject line to the mail file

		MOVE T1,CPYJFN		;Get JFN of the mail file
		HRROI T2,[ASCIZ/Subject: /]
		SETZ T3,		;ASCIZ
		SOUT			;Copy the string to the mail file
		ERJMP .+1		;Should not happen
		MOVE T1,CPYJFN		;Get JFN of the mail file
		MOVE T2,Q2		;Pointer to the subject line
		SETZ T3,		;ASCIZ
		SOUT			;Copy the string to the mail file
		ERJMP .+1		;Should not happen
		RET
	;Build and place the message ID in the mail file

	BLDMID:	MOVE T1,CPYJFN		;Get JFN of the message file
		HRROI T2,[ASCIZ/
	Message-ID: <"ARMAIL" /]
		SETZ T3,		;ASCIZ string
		SOUT
		ERJMP .+1		;Should not happen
		MOVE Q1,CURPTR		;Where to place the message ID
		MOVEI Q2,"."		;For convience
		GTAD			;Get the current date
		CALL CONVRT		;Convert to ASCIZ	
		IDPB Q2,Q1		;Add date delimiter
		GJINF			;Get the job number and user number
		PUSH P,T1		;Save user number for awhile
		MOVE T1,T3		;Place the job number where CONVRT expects it
		CALL CONVRT		;Convert job number to ASCIZ
		IDPB Q2,Q1		;Add job number delimiter
		POP P,T1		;Restore the user number
		HRRZS T1		;Want only the right half
		CALL CONVRT		;Convert user number to ASCIZ
		IDPB Q2,Q1		;Add user number delimiter
		SETO T1,		;For this job
		MOVE T2,[-1,,Q3]	;Place runtime in Q3
		MOVEI T3,.JIRT		;Want the run time
		GETJI			;Get the run time
		SETZ Q3,		;Give zero for an error
		HRRZ T1,Q3		;Want only the right half
		CALL CONVRT		;Convert runtime to ASCIZ
		
		MOVEI T1," "		;Separate previous info
		IDPB T1,Q1		;From the node name
		MOVEI T2,"a"
		IDPB T2,Q1
		MOVEI T2,"t"
		IDPB T2,Q1
		IDPB T1,Q1
		MOVE T1,NODPTR		;Get pointer to the node name
	NDNAME:	ILDB T2,T1		;Get the next character
		IDPB T2,Q1		;Place in the current buffer
		CAIE T2,0		;Finished?
		JRST NDNAME		;No, get the next character
		MOVEI T1,">"		;Terminate the string
		DPB T1,Q1		;Overwrite the null
		MOVEI T1,15		;Get a carriage return
		MOVEI T2,12		;And a line feed
		IDPB T1,Q1		;Add a blank line
		IDPB T2,Q1
		IDPB T1,Q1
		IDPB T2,Q1
		SETZ T1,		;Make it ASCIZ
		IDPB T1,Q1

		MOVE T1,CPYJFN		;Get the JFN of the mail file
		MOVE T2,CURPTR		;The string to copy
		SETZ T3,		;ASCIZ
		SOUT			;Copy the string to the mail file
		ERJMP .+1		;This should not happen

	CONVRT:	IDIVI T1,^D10		;Pick off a digit
		PUSH P,T2		;Save for awhile
		SKIPE T1		;Finished?
		CALL CONVRT		;No, get the next digit
		POP P,T1		;Yes,pick up the next digit from the stack
		ADDI T1,"0"		;Make it ASCII
		IDPB T1,Q1		;Place in the buffer
		RET
	;Place the text into the mail file. Add a delimiter and  close the mail file

	BLDTXT:	MOVE T1,ARGPTR		;Get the argument block
		MOVE T2,2(T1)		;Get the pointer to the text
		TLC T2,-1
		TLCN T2,-1		;Of form -1,,ADDR ?
		HRLI T2,(POINT 7)	;Yes, convert to PDP-10 byte pointer
		MOVE T1,CPYJFN		;Get the JFN of the mail file
		SETZ T3,		;ASCIZ string
		SOUT			;Copy the text to the mail file
		ERJMP .+1		;Should not happen

		MOVE T1,CPYJFN		;Get the JFN of the mail file
		HRROI T2,[ASCIZ/
	   --------
	/]
		SETZ T3,		;ASCIZ
		SOUT			;Copy the delimiter over
		ERJMP .+1		;Should not happen

		MOVE T1,CPYJFN		;Get the JFN of the mail file
		TXO T1,CO%NRJ		;Do not release the JFN
		CLOSF			;Close it
		ERJMP [RET]		;Can't close the mail file, quit
		RETSKP

	;Build the file spec record

	BLDSPC:	SETZ P1,		;No bytes in this record yet
		MOVEI T2,FILSPC		;Address of the file spec
		HRLI T2,(POINT 7)	;Make into a pointer
		MOVE T4,P5		;Address of the record
		ADDI T4,.RECHS		;Address of the file spec field
		HRLI T4,(POINT 7)	;Make it into a pointer
	TRSFIL:	ILDB T1,T2		;Get the next character
		IDPB T1,T4		;Place in the file spec record
		AOS P1			;Increment the byte count
		CAIE T1,0		;End of the string?
		JRST TRSFIL		;No, continue
		IDIVI P1,5		;Find the number of words
		SKIPE P2		;A partial word?
		AOS P1			;Yes, count as a word
		ADDI P1,.RECHS		;Include the header size
		MOVEM P1,.RECLN(P5)	;Place length in record
		AOS T1,MSGRCT		;Increment the record count
		MOVEM T1,.RECNM(P5)	;Place in record
		MOVEI T1,.FLSPC		;Get record type
		MOVEM T1,.RECTY(P5)	;Place in the record
		RET
	;Send the message page to MX

	SNDMX:	CALL SNDOFF		;Page is full, send off to MX
		RET			;An error occurred, quit
		RETSKP			;No errors
	;Build the message header record then send off to MX

	SNDOFF:	MOVEI P5,IPCPGS		;Address of header record
		MOVEI T1,.POST		;Assume first page
		SKIPE IDNUM		;First page?
		MOVEI T1,.CONT		;No, indicate so
		MOVEM T1,.PKTYP(P5)	;Place in the header record
		MOVE T1,IDNUM		;Pick up the message ID
		MOVEM T1,.PKID(P5)	;Place in the message
		AOS T1,MSGNUM		;Increment the message page number
		MOVEM T1,.PKSEQ(P5)	;Place in the message
		MOVEI T1,.DONE		;Assume no more pages
		SKIPN PAKSTS		;Is this true?
		MOVEI T1,.MORE		;No, more to follow
		MOVEM T1,.PKSTS(P5)	;Store in the message
		MOVE T1,MSGRCT		;Pick up the number of records 
		MOVEM T1,.PKRCT(P5)	;Place in the message

	;Send the message off to MX

		MOVX T1,IP%CFV		;Page mode
		MOVEM T1,PDB+.IPCFL	;Place in the flag word
		MOVE T1,MYPID		;Pick up our PID
		MOVEM T1,PDB+.IPCFS	;Place in the sender word
		MOVE T1,MLRPID		;Pick up MX' PID
		MOVEM T1,PDB+.IPCFR	;Place in the receiver word
		MOVEI T1,IPCPGS		;Address of the message
		LSH T1,-^D9		;Change to page number
		HRLI T1,1000		;Size of the message
		MOVEM T1,PDB+.IPCFP	;Place in the packet address word
		MOVEI T1,4		;Size of the packet descriptor block
		MOVEI T2,PDB		;Address of the PDB
		MSEND			;Send the message to MX
		ERJMP GIVUP		;Can't, so give up

	;Get the reply from MX

		MOVEI Q1,10		;Retry count
		MOVX T1,IP%CFB!IP%CFV	;Do not block, expecting a page
		MOVEM T1,PDB+.IPCFL	;Store in the flag word
		MOVE T1,MYPID		;Pick up our PID
		MOVEM T1,PDB+.IPCFR	;Place in the receiver word
	NOTFMX:	SETZM PDB+.IPCFS	;INFO will fill in the sender's PID
	TRYMOR:	MOVEI T1,4		;Length of the PDB
		MOVEI T2,PDB		;Address of the PDB
		MRECV			;See if we have a message
		ERJMP [ SOJLE Q1,GIVUP		;Time to give up?
			MOVEI T1,^D1000		;No, sleep a second
			DISMS
			JRST TRYMOR]		;Try again
		MOVE T1,PDB+.IPCFS	;Get the PID of the sender
		CAME T1,MLRPID		;From MX?
		JRST NOTFMX		;Try again
		HRRZ P5,PDB+.IPCFP	;Get the message page number
		LSH P5,^D9		;Make it into an address
		MOVE T1,.PKSTS(P5)	;Get the status word
		CAIN T1,.STABD		;Did MX abort it?
		JRST GIVUP		;Yes, give up
		SKIPE PAKSTS		;More pages to follow
		JRST FINSND		;No, return success

	;Set up for the next page

		MOVE T1,.PKID(P5)	;Get the message ID
		MOVEM T1,IDNUM		;Save for later
		SETZM MSGRCT		;No records yet in this message
		MOVEI P3,.HDRSZ		;Global word count for this message
		MOVEI P5,IPCPGS+.HDRSZ	;Address of the current record
	FINSND:	RETSKP			
	GIVUP:	RET
 REP 12/15	;15C19
		 JFCL
		RET

	;Some hacks to not need MACREL
 WIT
		 ERJMP .+1 
		RET
	; Routine to save and restore the AC's.

	SAVACS:	MOVEM P,SAVAC+17	; Save all accumulators
		MOVEI P,SAVAC		
		BLT P,SAVAC+16
		MOVE P,SAVAC+17		; Get back the stack pointer
		POP P,T3		; Get the return address
		MOVEM P,SAVAC+17	; Save original stack before call to ARMAIL
		PUSH P,[SVACRT]		; Routine to restore the accumulators
		PUSH P,T3		; Go back to caller of this routine
		RET

	SVACRT:	SKIPA			; If RET return, skip adding to the PC
		AOS SAVAC+17		; RETSKP
		MOVSI P,SAVAC		; Restore the accumulators
		BLT P,P
		RET

	;Some hacks do not need MACREL
 SUM 63701