Google
 

Trailing-Edge - PDP-10 Archives - BB-JF18A-BM - sources/mx/smtsen.mac
There are 21 other files named smtsen.mac in the archive. Click here to see a list.
	TITLE	SENDER	- SMTP Sender
	TWOSEG
	RELOC	400000
;Call with the address of the work request and the common info block address
; on the stack.  Returns the status in T1 and in the work request.

	SEARCH	MACSYM

	EXTERN	DB%VD8,NODNAM,UF%CLO,UN%OPE,ER%PRC
	EXTERN	UF%OPE,UF%REA,UM%GET,UM%REL,UN%CLO,UN%REA,UN%WRI,MXERRS
	EXTERN	MG$GPE,MG$MFC,NMLDIE,LOG

	INTERN	SMTPSN

	FTLOG==0
;Various offsets and values for MX data structures
	.DESTN==3
	.FILSP==1
	.POST==1
	.SENDR==2

	.RECNM==0
	.RECTY==1
	.RECLE==2
	.RECTX==3

	.PKTYP==0
	.PKID==1
	.PKSEQ==2
	.PKSTS==3
	.PKRCT==4

;AC's
	F==0
	T1==1
	T2==2
	T3==3
	T4==4
	T5==5
	T6==6
	CONBLK==7		;ADDRESS OF A CONNECT BLOCK
	CMNBLK==10		;ADDRESS OF COMMON INFO BLOCK
	WRKREQ==11		;ADDRESS OF WORK REQUEST BLOCK
	RCPTPT==12		;POINTER TO NODENAME
;DO NOT USE 13
	DECNET==14		;DECNET LINK NUMBER
;DO NOT USE 15
	VR==16			;POINTER TO VARIABLE SPACE
	P==17

;FLAGS
	F.N421==1B0		;IF NOT TRAPPING THE 421 RESPONSE
	F.NOTS==1B1		;NOT SURE IF SMTP YET

;WHAT TO TELL MX WHEN THE TRANSACTION'S DONE (OR DEAD)
	.NOOBJ==-2		;NO MX AT REMOTE NODE
	.DONE==2		;POSTED THERE, WE CAN DROP THE REQUEST
	.RETRY==3		;RETRY LATER, THEY HAD PROBLEMS
	.FAIL==5		;THEY CAN'T HANDLE THIS AT ALL, COMPLAIN

;OFFSETS INTO BLOCK OF INFORMATION AT VR
	TMPPTR==0		;POINTER TO TEMP. STRING SPACE
	CMDPTR==1		;POINTER TO COMMAND TO SEND
	GIVFRM==2		;POINTER TO GIVEN "FROM" STRING
	MSGPTR==3		;POINTER INTO CMDPTR, REAL TEXT TO SEND
	FRMPTR==4		;FROM STRING
	TXTPTR==5		;TEXT FROM LISTENER
	TXTLEN==6		;LENGTH OF TEXT
	FILE==7			;FILE NUMBER, 0 MEANS TEXT ISN'T FROM A FILE
	OUTCNT==10		;CHARACTERS IN OUTPUT BUFFER
	SAVAC==11		;SPACE FOR AC SAVES FOR BLISS
	N%VAR=11+4+1		;NUMBER OF VARIABLES NEEDED

	MAXOUT==^D1300
	MAXSTR==^D1000
	CONLEN==^D64		;LENGTH OF A CONNECT BLOCK

	define logger(txt),<
 IFN FTLOG,<
	CALL	[PUSH	P,[ -1,,[ASCIZ/
**********	txt
/]]
		call	logers
		adjsp	p,-1
		RET]
> >
	define logget(addr),<
 IFN FTLOG,<
	CALL	[PUSH	P,addr
		 call	logers
		 adjsp	p,-1
		RET]
> >	


IFN FTLOG,<
logers:	PUSH	P,T1
	PUSH	P,T2
	MOVX	T1,GJ%SHT+GJ%OLD
	HRROI	T2,[ASCIZ/MX:SMTSEN.LOG/]
	GTJFN%
	 ERJMP	NOLOGR
	MOVX	T2,OF%APP+7B5
	OPENF%
	 ERJMPS	NOLOGX
	PUSH	P,T3
	SETZ	T3,
	move	t2,-4(p)
	sout%
	 erjmps	.+1
	pop	p,T3
nologx:	closf%
	 erjmps	.+1
nologr:	pop	p,t2
	pop	p,t1
	ret
>

;SAVE MANY AC'S AT START
SMTPSN:	MOVE	T2,P			;FRAME POINTER OF SORTS
	PUSH	P,0
	PUSH	P,6			;SAVE ACS FOR BLISS
	PUSH	P,7
	PUSH	P,10
	PUSH	P,11
	PUSH	P,12
	PUSH	P,14
	PUSH	P,16

	MOVE	WRKREQ,-2(T2)		;FETCH WORK REQUEST
	MOVE	T1,[-1000]
	MOVEM	T1,5(WRKREQ)		;set "impossible" value in status word
	MOVE	CMNBLK,-1(T2)		;CALLER PASSES COMMON BLOCK ADDRESS

	PUSH	P,[N%VAR]		;GET VARIABLE SPACE
	CALL	UM%GET
	ADJSP	P,-1
	SKIPN	VR,T1			;STORE POINTERS TO VARIABLES
	CALL	NOMEME			;NO MEMORY??
	SETZB	DECNET,FILE(VR)		;NO FILE YET, NO LINK
	SETZB	F,CONBLK		;NO FLAGS ON YET

	PUSH	P,[<SENMEM=CONLEN+3*<MAXSTR/5+1>+<MAXOUT/5+1>+1>]
	CALL	SVACSE
	CALL	UM%GET
	CALL	RSACSE
	ADJSP	P,-1
	SKIPN	CONBLK,T1
	CALL	NOMEME
	ADD	T1,[POINT 7,CONLEN]	;SET UP STRING SPACE AND POINTERS
	MOVEM	T1,TXTPTR(VR)
	ADDI	T1,MAXOUT/5+1
	MOVEM	T1,CMDPTR(VR)
	ADDI	T1,MAXSTR/5+1
	MOVEM	T1,FRMPTR(VR)
	ADDI	T1,MAXSTR/5+1
	MOVEM	T1,TMPPTR(VR)

	 logger	<SMTSEN starting up...>

	HLRZ	RCPTPT,4(WRKREQ)	;GET SENDER
	JUMPE	RCPTPT,DONE		;NO SENDERS! THAT WAS EASY...
	HLRZ	T1,(CMNBLK)		;POINTER TO FILENAME
	LDB	T2,[POINT 7,(T1),6]	;SNAG FIRST CHARACTER OF FILENAME
	CAIN	T2,";"			;IS IT NOT A FILENAME?
	JRST	SEND1			;YES, THIS IS SEND, NOT MAIL
	HRLI	T1,(POINT 7)		;MAKE A BP
	PUSH	P,T1			;STORE FILENAME
	PUSH	P,[1]			;STORE READ REQUEST
	PUSH	P,[0]			;DON'T WANT ERROR INFO
	CALL	SVACSE
	CALL	UF%OPE			;OPEN IT
	CALL	RSACSE
	ADJSP	P,-3			;TOSS ARGS
	JUMPLE	T1,DONE			;NO FILE? WE ARE DONE..
	MOVEM	T1,FILE(VR)

SEND1:	HRRZ	T4,1(CMNBLK)		;GET "FROM" STRING
	HRLI	T4,(POINT 7)		;PREPARE TO SCAN IT
	MOVEM	T4,GIVFRM(VR)		;STORE STRING POINTER AT GIVFRM
SCANAT:	ILDB	T2,T4			;LOOK FOR "@" OR <NUL>
	JUMPE	T2,NOATSI		;NO "@", SO JUST A USER NAME
	CAIE	T2,"@"
	JRST	SCANAT			;KEEP LOOKING
	SKIPA	T5,TMPPTR(VR)
FNDENN:	IDPB	T2,T5
	ILDB	T2,T4			;LOOK FOR NODENAME TERMINATIOR
	CAIE	T2,","
	CAIN	T2,":"
	TDZA	T2,T2
	JUMPN	T2,FNDENN
	IDPB	T2,T5
	PUSH	P,TMPPTR(VR)		;SET UP TO VALIDATE FIRST NODE SEEN
	PUSH	P,[1]
	PUSH	P,[-1]
	CALL	SVACSE
	CALL	DB%VD8
	CALL	RSACSE
	ADJSP	P,-3
	JUMPE	T1,OURNDE		;0 IF IT WAS A LOCAL NODE
	MOVEI	T3,"@"			;NOT LOCAL (OR NOT KNOWN)
	MOVE	T2,FRMPTR(VR)		;SO PREPEND @OURNAME {,|:} TO STRING
	IDPB	T3,T2			;BUILD "@" + OURNODENAME
	MOVE	T1,[POINT 7,NODNAM]
	CALL	CSTRB
	MOVE	T4,GIVFRM(VR)		;POINT TO FIRST CHAR OF GIVEN FROM
	MOVE	T1,T4			;WILL WANT THIS SOON
	ILDB	T5,T4			;WHAT IS IT? @ OR USERNAME?
	MOVEI	T3,":"			;ASSUME FIRST ADDITION
	CAIN	T5,"@"			;@ MEANS ALREADY FORWARDED...
	MOVEI	T3,","			;SO USE , INSTEAD
	IDPB	T3,T2			;PUT CHARACTER IN
	CALL	CSTR			;FINISH BUILDING THS STRING
	JRST	GOTFRM			;OK, GOT THE FROM STRING
OURNDE:	MOVE	T1,GIVFRM(VR)		;OUR NODE, JUST COPY IT VERBATIM
	MOVE	T2,FRMPTR(VR)
	CALL	CSTR
	JRST	GOTFRM
NOATSI:	MOVE	T2,FRMPTR(VR)		;JUST A USER NAME, COPY IT
	MOVE	T1,GIVFRM(VR)
	CALL	CSTRB
	MOVEI	T3,"@"			;AND ADD @OURNODENAME
	IDPB	T3,T2
	MOVE	T1,[POINT 7,NODNAM]
	CALL	CSTR
GOTFRM:
	HRRZ	T2,4(WRKREQ)		;POINTER TO NODE TO CONNECT TO
	HRLI	T2,(POINT 8)
	MOVEM	T2,0(CONBLK)		;STORE TO WHERE STRING WILL GO
	IBP	T2
	IBP	T2			;SKIP 2 NULLS
	ILDB	T4,T2			;FETCH LENGTH
	MOVEM	T4,1(CONBLK)		;STORE

	SETZM	2(CONBLK)		;CLEAR EVERYTHING ELSE
	MOVSI	T1,2(CONBLK)		;..
	HRRI	T1,3(CONBLK)		;..
	BLT	T1,CONLEN-1(CONBLK)	;..
;
;SET UP A SOURCE TASK NAME IN CB_TASK
;
	MOVE	T1,[POINT 7,[ASCII /MX-SENDER/]]	;Who we are
	MOVEM	T1,3(CONBLK)
	MOVEI	T1,^D9			;LENGTH OF ABOVE TASK NAME
	MOVEM	T1,4(CONBLK)

;
;SET UP A TARGET TASK NAME IN CB_DESCRIPTOR
;
	MOVE	T1,[POINT 7,[ASCII /MX-LISTENER/]]	;Who we want to talk to
	MOVEM	T1,15(CONBLK)
	MOVEI	T1,^D11			;LENGTH OF ABOVE TASK NAME
	MOVEM	T1,16(CONBLK)

	PUSH	P,[2]			;CONNECT TYPE 2, SOURCE
	PUSH	P,CONBLK
	PUSH	P,[0]
	PUSH	P,[0]
	PUSH	P,[0]
	CALL	SVACSE
	CALL	UN%OPEN			;HELLO, REMOTE MX
	CALL	RSACSE
	ADJSP	P,-5
	SKIPG	DECNET,T1		;GOT LINK?
	JRST	NOSMTP			;NO...
	TXO	F,F.NOTS		;NOT SURE IF SMTP LISTENER YET...
;Here we will wait for the destination to send us "220", meaning "Yes,
; I am a SMTP listener and I am alive". We JRST to DNTINR with T2
; pointing to a vector of 5 possible addresses, which we jump to
; according to the response we get: 1xx, 2xx, 3xx, 4xx, 5xx. The actual
; response code ends up in T1. If we get total garbage, we go straight
; to BADRSP.
	MOVEI	T2,[EXP RETRY,MAYBE,RETRY,RETRY,RETRY]
	JRST	DNTINR			;GET SOME INPUT AND DISPATCH

MAYBE:	CAIE	T1,^D220		;PROPER STARTUP MESSAGE?
	JRST	RETRY			;NO, BAG IT
	SETZ	T4,			;YES, RESPOND
	TXZ	F,F.NOTS		;OK, IT IS CERTAINLY SMTP
	HRROI	T1,[ASCIZ/HELO /]	;SO BUILD HELO COMMAND
	MOVE	T2,CMDPTR(VR)
	CALL	CSTRB
	MOVE	T1,[POINT 7,NODNAM]	;"HELO <nodename> READY"
	CALL	CSTRB
	HRROI	T1,[ASCIZ/ Ready
/]
	CALL	CSTR
	MOVE	T1,CMDPTR(VR)		;T1/BP, T2/ DISPATCH VECTOR, T4/ LENGTH
;We expect a "250", anything else causes a RSET and we'll tell MX to try
; again later
	MOVEI	T2,[EXP RSTRTY,HELOOK,RSTRTY,RSTRTY,RSTRTX]
	JRST	OUTCMD			;AND SEND AND DISPATCH ON RESPONSE

RSTRTX: logger	<Protocol error on Startup>
	PUSH	P,[[ASCIZ/SMTSEN: Protocol error on startup/]]
	CALL	LOG
	ADJSP	P,-1
;HERE TO RESET AND GO TO RETRY (IE, WE GOT TOLD WE CAN'T GO ON NOW)
RSTRTY:	HRROI	T1,[ASCIZ/RSET
/]
	MOVEI	T4,6			;LENGTH IS 6 CHARS
	MOVEI	T2,[EXP 0,RETRY]	;ALWAYS GO TO RETRY
;A DISPATCH VERTOR OF THE FOPRM 0,ADDR MEANS ALWAYS GO TO ADDR ON ANY NUMERIC
; RESPONSE
	JRST	OUTCMD			;SEND THE RSET

;BUILD A "MAIL FROM:" COMMAND
HELOOK:	SETZ	T4,
	HRROI	T1,[ASCIZ/MAIL FROM:/]
	SKIPN	FILE(VR)		;IS THIS A SEND COMMAND?
	HRROI	T1,[ASCIZ/SEZZ FROM:/]	;YUP
	MOVE	T2,CMDPTR(VR)
	CALL	CSTRB
	MOVE	T1,FRMPTR(VR)		;GET FROM STRING
	CALL	CSTRB
	HRROI	T1,CRLF			;TERMINATE PROPERLY
	CALL	CSTR
	MOVE	T1,CMDPTR(VR)
	MOVEI	T2,[EXP RSTRTY,DORECV,RSTRTY,RSTRTY,RSTRTY]
	JRST	OUTCMD

DORECV:	SETZ	T6,			;COUNT "OK" RECIPIENTS
RECEIL:	SETZ	T4,			;COUNT STRING LENGTH
	HRROI	T1,[ASCIZ/RCPT TO:</]
	MOVE	T2,CMDPTR(VR)
	CALL	CSTRB
	HLRO	T1,(RCPTPT)
	CALL	CSTRB
	HRROI	T1,[ASCIZ/>
/]
	CALL	CSTR			;STRING IS ENCLOSED IN <>
;1xx, 3xx and 4xx imply Try Again Later; 2xx is OK; 5xx is Sorry Not Here
	MOVEI	T2,[EXP RSTRTY,ACCPT,RSTRTY,RSTRTY,FLUNK]
	MOVE	T1,CMDPTR(VR)	;SEND WHAT WE BUILT
	JRST	OUTCMD

;Format up a complaint message. This mail can't be delivered.
FLUNK:	MOVEI	T1,1(P)
	PUSH	P,[6]
	PUSH	P,[1B3+2B17+1B18+<MG$GPE>B32+4B35]
	PUSH	P,2(WRKREQ)
	PUSH	P,[0]
	PUSH	P,[2]
	PUSH	P,[POINT 7,[ASCIZ /SMTP/]]
	PUSH	P,TXTPTR(VR)
	PUSH	P,T1
	CALL	ER%PRC
	ADJSP	P,-8
	 logger	<At FLUNK, username not allowed at remote>
	JRST	SKIPON		;OK, TRY TO DELIVER TO TNE NEXT RECPIENT

ACCPT:	ADDI	T6,1		;ACCEPTED, COUNT ANOTHER GOOD ONE
SKIPON:	HRRZ	RCPTPT,(RCPTPT)	;GET NEXT USER
	JUMPN	RCPTPT,RECEIL	;IF THERE IS ONE, GO BACK AND HANDLE
	JUMPE	T6,NOSEND	;GOT *ANY* GOOD USERS?
	HRROI	T1,[ASCIZ/DATA
/]
	MOVEI	T4,6		;YES. SEND THE "DATA" COMMAND
;ALLOW 2xx and 3xx (354 is the correct value)
	MOVEI	T2,[EXP RSTRTY,DATAGO,DATAGO,RSTRTY,RSTRTY]
	JRST	OUTCMD

;Here to read the message file and ship it over, adding any "."s at the
;beginning of lines that require them.
DATAGO:	SETO	T6,		;SAY AT THE BEGINNING OF A LINE
	SETZM	OUTCNT(VR)	;NO CHARACTERS IN OUT BUFFER YET
	MOVE	T1,CMDPTR(VR)	;INIT OUT BUFFER POINTER
	MOVEM	T1,MSGPTR(VR)	;..
	 logger	<Shoving DATA out...>
FILLBF:	SKIPE	T1,FILE(VR)
	JRST	NORMML		;NORMAIL MAIL
	HLRZ	T3,(CMNBLK)	;GET THE POINTER TO THE MESSAGE
	HRLI	T3,(POINT 7,0,6);..
	LDB	T2,T3		;GET THAT FIRST CHARACTER
	CAIE	T2,";"		;ALREADY DONE THIS?
	JRST	[MOVEI	T2,";"
		 DPB	T2,T3	;YES, REPAIR STRING..
		 JRST	EOFFIL]	;AND LEAVE
	MOVEI	T2,"!"		;CHANGE THE STRING BRIEFLY
	DPB	T2,T3		;SO WE KNOW WE DID IT.
	SETZ	T4,		;WE NEED THE STRING LENGTH
	MOVE	T1,T3
CNTSND:	ILDB	T2,T1
	CAIN	T2,.CHLFD	;LINEFEED IS THE LAST CHARACTER
	AOJA	T4,GCHARM	;COUNT IT AND LEAVE
	JUMPE	T2,GCHARM	;IN CASE OF WIERDNESS
	AOJA	T4,CNTSND

NORMML:	PUSH	P,FILE(VR)	;READ A BUFFER FROM THE FILE
	PUSH	P,TMPPTR(VR)
	PUSH	P,[MAXOUT]	;BIG CHUNK
	PUSH	P,[0]
	CALL	SVACSE
	CALL	UF%REA		;THIS READS SINGLE LINES, SADLY
	CALL	RSACSE
	ADJSP	P,-4
	SKIPN	T4,T1		;GET COUNT INTO T4
	JRST	EOFFIL		;0 MEANS EOF, GO EMPTY OUTPUT BUFFER, ETC.
	JUMPL	T4,FREAK	;FILE ERROR? SERIOUS STUFF
	MOVE	T3,TMPPTR(VR)	;GET POINTER TO INPUT BUFFER
GCHARM:	SOJL	T4,FILLBF	;COUNT OFF A CHARACTER; IF NONE, REFIL BUFFER
	ILDB	T1,T3		;GRAB OUR CHARACTER
	CAIN	T1,.CHLFD	;LINE ENDING?
	JRST	[SETO	T6,	;FLAG: NEXT CHARACTER STARTS A NEW LINE
		 JRST	WRICHR]	;GO OUTPUT IT
NORCHR:	JUMPE	T6,WRICHR	;ARE WE STARTING A LINE?
	CAIE	T1,"."		;YES. DO WE WANT TO SEND A DOT?
WRICH0:	TDZA	T6,T6		;NO. HERE TO SEND A REGULAR CHARACTER
	MOVEI	T6,1		;HERE TO SEND DOUBLED DOT
WRICHR:	IDPB	T1,MSGPTR(VR)	;OUTPUT THE CHARACTER
	AOS	T2,OUTCNT(VR)	;ANOTHER ONE IN..
	CAIGE	T2,MAXOUT-^D135	;BUFFER GETTING FULL?
	JRST	CHKREP		;NO, FINISH STORE OF CHARACTER
	JUMPL	T6,DUMPIT	;YES, IF WE JUST READ A <LF> GO DUMP BUFFER
;We endeavour to send buffers that end on a line boundary, just for neatness.
;If we can't, though, we don't.
	CAIGE	T2,MAXOUT-1	;IS BUFFER *VERY* FULL?
	JRST	CHKREP		;NO, KEEP GOING (HOPING FOR A <LF>)
DUMPIT:	CALL	DUMPDT		;DUMP THE BUFFER OVER THE WIRE
	 JRST	FAILED		;UH-OH
CHKREP:	JUMPLE	T6,GCHARM	;IF T6 .LE. 0, GET NEXT CHARACTER
	MOVEI	T1,"."		;ELSE, SEND ANOTHER DOT
	JRST	WRICH0		;AND THEN GET NEXT CHARACTER

DUMPDT:	MOVE	T1,CMDPTR(VR)	;SEND TEXT REF'D BY T1
	EXCH	T4,OUTCNT(VR)	;SAVE T4. T4 NOW HAS NUMBER OF CHARS TO DUMP
	CAIG	T4,0		;ARE THERE ANY?
	SKIPA	T1,[1]		;NO, FAKE A GOOD RETURN
	CALL	DTNOUT		;YES, SEND THEM
	MOVE	T4,OUTCNT(VR)	;RESTORE T4
	MOVE	T2,CMDPTR(VR)	;SET UP A NEW OUTPUT BUFFER POINTER
	MOVEM	T2,MSGPTR(VR)	;..
	SETZM	OUTCNT(VR)	;AND SAY "EMPTY"
	TRNE	T1,1		;WAS THE OUTPUT OK?
	AOS	(P)		;SKIP IF OK
	RET			;UH-OH

;FILE CORRUPTION. SAY WE CAN'T DELIVER
FREAK:	PUSH	P,[[		;Push address of complaint string
 ASCIZ/	SMTSEN:	File corruption in outgoing mail, aborting/]]
	CALL	LOG
	ADJSP	P,-1
	 logger	<At FREAK, file corruption>
	MOVEI	T1,1(P)
	PUSH	P,[4]
	PUSH	P,[1B3+2B17+1B18+<MG$MFC>B32+4B35]
	PUSH	P,2(WRKREQ)
	PUSH	P,[0]
	PUSH	P,[0]
	PUSH	P,T1
	CALL	ER%PRC
	ADJSP	P,-6
	JRST	FAILED		;AND ABORT THIS MESS

;Reached EOF. Send the contents of the output buffer, and then send the
; termination sequence (.<CR> AFTER A <LF>)
EOFFIL:	CALL	DUMPDT	;DUMP WHAT WE HAVE
	 JRST	FAILED
	JUMPL	T6,FINMSG	;LAST CHARACTER SHOULD HAVE BEEN A <LF>
	 logger	<Last character wasn't a CRLF, sending an extra LF>
	MOVEI	T1,.CHLFD	;REALLY! WELL, SEND ONE NOW..
	IDPB	T1,MSGPTR(VR)
	AOS	OUTCNT(VR)
	CALL	DUMPDT
	 JRST	FAILED
FINMSG:	HRROI	T1,[BYTE(7) ".", .CHCRT, .CHLFD] ;TERMINATED STRING
	MOVEI	T4,3		;LENGTH OF 3
	MOVEI	T2,[EXP NOSEND,DONE,NOSEND,NOSEND,NOSEND]
	 logger	<Dumping dot terminator>
	JRST	OUTCMD

;HERE IF WE GET A FAIL RETURN
NOSEND:	HRROI	T1,[ASCIZ/RSET
/]
	MOVEI	T4,6		;6 CHARS
	MOVEI	T2,[EXP 0,FAILED]
	 logger	<Got to NOSEND!>
	JRST	OUTCMD


;OUTCMD should be jrst'd to, not called.
; It sends a string and waits for a response, and dispatches according
; to the given address vector on the response.
;T1/ STRING POINTER (CAN BE -1,,ADDR)
;T2/ ADDRESS VECTOR (5 ADDRESSES, OR EXP 0,ONLY-RETURN-ADDRESS)
;T4/ NUMBER OF CHARACTERS TO SEND
;F/ F.N421 IF LIT, PASS 421 TO CALLER (DON'T TRAP IT)
; May not return (on a bad response). If it returns, T1 contains the
; response value.
OUTCMD:	CALL	DTNOUT
	TRNN	T1,1
	JRST	HUNGUP
	;JRST	DNTINR
;DNTINR - takes dispatch vector in T2.  Reads in a line, checks it for
; sanity, and dispatches accoring to T2, with T1/ number read.
DNTINR:	CALL	DNTIN
	MOVE	T1,TXTPTR(VR)		;GET POINTER TO TEXT
	SETZ	T3,
DECCHK:	ILDB	T4,T1
	CAIL	T4,"0"
	CAILE	T4,"9"
	JRST	CHKVCM
	IMULI	T3,^D10
	ADDI	T3,-"0"(T4)
	CAIG	T3,^D599	;IF ALREADY OUT OF RANGE, GIVE UP
	JRST	DECCHK
	JRST	BADRSP
CHKVCM:	CAIGE	T3,^D100
	JRST	BADRSP		;IF TOO SMALL, NO GOOD
	MOVE	T1,T3		;SAVE VALUE FOR CALLER
	TXNE	F,F.N421	;LOOKING FOR A 421 RESPONSE?
	JRST	PASSIT		;WE SHOULD PASS IT BACK
	CAIN	T1,^D421	;TRAP THEM.  IS THIS ONE?
	JRST	FADING		;YES. THE LISTENER IS RUNNING OUT OF TIME
PASSIT:	IDIVI	T3,^D100	;GET FIRST DIGIT IN T3
	SKIPN	(T2)		;IS THIS A SPECIAL LIST?
	JRST	@1(T2)		;YES, JUMP TO SECOND ADDRESS
	ADDI	T2,-1(T3)	;ADD ONE LESS TO ADDRESS IN T2
	JRST	@(T2)		;GO TO ADDRESS FOR THAT RESPONSE
FADING:	MOVEI	T2,[EXP 0,HUNGUP]
	TXO	F,F.N421	;SEND HIM QUIT, AND ON ANY RESPONSE, HANGUP
	HRROI	T1,[ASCIZ/QUIT
/]
	MOVEI	T4,6
	JRST	OUTCMD

;Call with T1 as byte pointer, T4 as length of string. Returns T1/ 1 if OK
; 0 otherwise.
DTNOUT:	TLC	T1,-1
	TLCN	T1,-1
	HRLI	T1,(POINT 7)
	PUSH	P,DECNET
	PUSH	P,[1]
	PUSH	P,T4
	PUSH	P,T1
	CALL	SVACSE
	CALL	UN%WRI
	CALL	RSACSE
	ADJSP	P,-4
	RET

;Return a null terminated string starting at TXTPTR(VR)
;On a channel death, dispatch to DIENOW (does not return)
;Must preserve T2
DNTIN:	PUSH	P,DECNET
	PUSH	P,[MAXSTR+5]
	PUSH	P,TXTPTR(VR)
	CALL	SVACSE
	CALL	UN%READ
	CALL	RSACSE
	ADJSP	P,-3
	JUMPLE	T1,NOANSW
	MOVEM	T1,TXTLEN(VR)
	ADJBP	T1,TXTPTR(VR)
	SETZ	T3,
	IDPB	T3,T1
	 logget	TXTPTR(VR)
CPOPJ:	RET
NOANSW:	ADJSP	P,-1		;LOSE RETURN ADDRESS
	 LOGGER	<Got length of 0 or less from decnet input>
	JRST	HUNGUP		;OTHER HUNGUP, TIME TO QUIT
BADRSP:	PUSH	P,[[
ASCIZ/	SMTSEN:	Bad SMTP response seen, hanging up/]]
	CALL	LOG
	ADJSP	P,-1
HUNGUP:	PUSH	P,DECNET
	PUSH	P,[0]
	PUSH	P,[0]
	 logger	<Hanging up link>
	CALL	SVACSE
	CALL	UN%CLO		;DUMP DECNET LINK
	CALL	RSACSE
	ADJSP	P,-3
	SETZ	DECNET,
	PUSH	P,[[ASCIZ/SMTP(SEN):	HUNGUP connection/]]
	CALL	LOG
	ADJSP	P,-1
;	JRST	RETRY		;TRY AGAIN LATER
RETRY:	 logger	<Logging retry code>
	MOVX	T1,.RETRY
	TXZN	F,F.NOTS	;MESSUP ON FIRST CONNECT?
	JRST	SETRES		;NO, ASSUME THEY HAVE SMTP
	 logger	<Changed to a NO OBJECT ocde (error on first connect)>
NOSMTP:	MOVX	T1,.NOOBJ	;YES. HERE IF NO SMTP THERE, SAY SO
	JRST	SETRES
DONE:	 logger	<Logging a DONE>
	MOVX	T1,.DONE
	JRST	SETRES
FAILED:	MOVX	T1,.FAIL
	 logger	<Logging abject failure>
SETRES:	MOVE	T2,5(WRKREQ)
	CAMN	T2,[-1000]
	MOVEM	T1,5(WRKREQ)		;SET STATUS
	JUMPLE	DECNET,ENDALL		;DECNET OPEN? IF NOT, SKIP CLOSE
	HRROI	T1,[ASCIZ/QUIT
/]
	MOVEI	T4,6
	MOVEI	T2,[EXP 0,CLOSIT]	;TO CLOSIT IN ALL CASES
	JRST	OUTCMD
CLOSIT:	PUSH	P,DECNET
	PUSH	P,[0]
	PUSH	P,[0]
	CALL	SVACSE
	CALL	UN%CLO
	CALL	RSACSE
	ADJSP	P,-3
ENDALL:	SKIPN	T1,FILE(VR)
	JRST	NOFILE
	PUSH	P,T1
	PUSH	P,[0]	;CLOSE
	PUSH	P,[0]	;DON'T WANT ERROR STRING
	CALL	SVACSE
	CALL	UF%CLO
	CALL	RSACSE
	ADJSP	P,-3
NOFILE:	PUSH	P,CONBLK
	PUSH	P,[SENMEM]
	CALL	UM%REL
	ADJSP	P,-2
	PUSH	P,VR
	PUSH	P,[N%VAR]
	CALL	UM%REL
	ADJSP	P,-2
	MOVE	T1,5(WRKREQ)		;RETURN OK OR FAILED OR DEFERED
SENEND:	POP	P,16
	POP	P,14
	POP	P,12
	POP	P,11
	POP	P,10
	POP	P,7
	POP	P,6
	POP	P,0
	RET				;RETURN TO CALLER


CSTR:	CALL	CSTRB
	IDPB	T3,T2
	RET

CSTRB:	TLCE	T1,-1
	TLCN	T1,-1
	HRLI	T1,(POINT 7)
	TLC	T2,-1
	TLCN	T2,-1
	HRLI	T2,(POINT 7)
CSTRC:	ILDB	T3,T1
	JUMPE	T3,CPOPJ
	IDPB	T3,T2
	AOJA	T4,CSTRC

CRLF:	ASCIZ/
/

RSACSE:	DMOVE	T2,SAVAC(VR)
	DMOVE	T4,SAVAC+2(VR)
	RET
SVACSE:	DMOVEM	T2,SAVAC(VR)
	DMOVEM	T4,SAVAC+2(VR)
	RET

NOMEME:	PUSH	P,[POINT 7,[ASCIZ/No memory at SMTSEN start up/]]
	CALL	NMLDIE
;NO RETURN
	END