;;; -*- Mode: MIDAS; Fonts: MEDFNT -*- NTSVER==.IFNM2 comment| NETSND - Send current msg (L) to all recipients for the host in N, using XRCP whenever possible. Assumes already "connected". | ; LIMRQS controls the # times a rcpt is allowed to temporarily fail. ; These are usually due to asshole hosts that blow out on control ; characters or long lines in the message text. Generally due to ; directory full on the local host, so try for a long time. LIMRQS: CAIG A,30. ; LIMRQS for remote hosts. CAIG A,200. ; LIMRQS for local host. (200 = about 3 days) NSMFLN: 2000. ; If message more chars than this, use MLFL BVAR ; NETSND variables NSCTQ: 0 ; On return, # of RCP's (must queue) NSCTF: 0 ; On return, # of RCPF's (failed, with A$RRMG's) NSCTS: 0 ; On return, # of RSNT's (sent, successful) NSSNT1: 0 ; -1 if "1st part done" for R or T mode. NSRHDR: 0 ; SPT to current header being used, 0 if none. NSRLST: 0 ; LP to list of VLN's indicating RCPTs done each pass. NSRRST: 0 ; LP to RCP to restart loop at with new header. EVAR SUBTTL NETSND ; NETSND - (assumes ICP already performed!) ; Sends message to all recipients for a specific host, taking ; advantage of XRCP whenever possible. ; L - Current LSE holding message. ; N - Site # being hacked. ; Returns with the following variables set: ; NSCTS - # of rcpts sent to (A$RCP changed to A$RSNT) ; NSCTF - # of rcpts failed (A$RCP changed to A$RCPF and failure ; message attached in A$RRMG.) ; NSCTQ - # of rcpts failed temporarily (unchanged). This will ; not include all rcpts if a non-skip return is made. ; Returns .+1 if host died or inactive, implying an abort. ; Returns .+2 if host still connected as far as NETSND knows. NETSND: PUSHAE P,[A,B,C,D,E,L] ; Initialize NETSND vars. SETZM NSCTQ ; Clear # of RCP's left after pass (to queue). SETZM NSCTF ; Clear # of RCPF's SETZM NSCTS ; Clear # of RSNT's SETZM NSSNT1 ; No "1st part done". SETZM NSRHDR ; No current header. SETZM NSRLST ; No list of RCP's done this pass. SETZM NSRRST ; No restart-RCP SETZM XRSQS ; Clear XRSQ scheme-to-use MOVE A,$LLLST(L) ; First see if want to as for XRSQ or not. CALL NSRFND ; Find a rcpt starting from LP in A. JRST [ CSTAT (,("... no rcpts for host!")) JRST NTSN95] ; No rcpts for this host? MOVE B,A ; Save 1st rcpt found JUMPE N,NTSN05 ; Needn't look for next if sending locally. HRRZ A,LISTAR(A) ; Get CDR CALL NSRFND ; and find next rcpt for this host. JRST NTSN05 ; No more? Just one rcpt, so don't hack XRSQ. ;; More than one rcpt for host, so it's worthwhile to hack XRSQ. SKIPN XRSQQ ; Already tried asking for pref? JRST [ PUSH P,B CALL NTXRSQ ; Nope, so go ask. NOP ; Net failure, but quit farther on. POP P,B JRST .+1] MOVE A,XRSQRS ; Get scheme that's been negotiated, MOVEM A,XRSQS ; and select that for hacking. ;; OK, we've got a scheme and there's someone to send to. ;; Do any low-level per-transaction initialization that is needed. NTSN05: JUMPE N,NTSN06 ; Not needed if really sending locally. TLNE F,%QULOS ; Nor if flushing this message JRST NTSN06 ;; Now setup for entry into loop, so that "next" rcpt is ;; first one. Still have LP in B to 1st rcpt... NTSN06: MOVEI E,(B) ; Set up E and skip over CDR-get, JRST NTSN12 ; for a little efficiency. ;; Main loop of NETSND. NTSN10: HRRZ E,LISTAR(E) ; Get CDR of rcpt just done, NTSN11: MOVEI A,(E) ; and search from that point CALL NSRFND ; to get a rcpt for this host. JRST NTSN50 ; No more this pass? Cleanup time... MOVEI E,(A) ; Save LP to the A$RCP. NTSN12: MOVE A,LISTAR(E)+1 ; Get LP to rcpt's list. TLNE F,%QULOS ; If we are flushing this message JRST [ MAKELN B,[0 ? %LTSTR,,[LITSTR [Host appears to be permanently down or not accepting mail.]]] JRST NTSN28 ] .ERR Move %QULOS feature elsewhere someday CALL SETMSM ; Set mail/send modes. Hope no SEND'ing! JUMPE N,[MOVE A,E ; If sending LOCALLY, then use CALL SNDMSG ; this routine, and on return JUMPE A,NTSN22 ; dispatch to right thing for win JRST NTSN25] ; or lose. SKIPE XRSQS JRST NTSN30 ; Go do either T or R mode. ;; Default scheme, no XRCP hacking. NTSN20: CALL NTMINI ; Initialize, mostly for SMTP. JRST NTSN80 ; Ugh! Abort this msg... MOVEI B,(C) ; Restore B MOVE A,LISTAR(E)+1 ; LP to rcpt list. CALL NTSBEG ; Give command & name to remote host. JRST NTSN25 ; Error of some kind, go investigate. MOVE A,LISTAR(E)+1 ; LP to rcpt list. CALL NTSMID ; Send header & text of message JRST NTSN25 ; Error of some kind, go investigate. CALL NTMEND ; Now terminate it and verify... JRST NTSN25 ; Foo. NTSN22: AOS NSCTS ; Win, bump count of sents. SKIPA B,[A$RSNT] ; Default mode success, NTSN24: MOVEI B,A$RCPF DPB B,[$LAFLD,,LISTAR(E)] ; say sent to this rcpt! TLO F,%MSGMD JRST NTSN10 ; Return to loop to get another. NTSN25: CAIE A,MR$PEH CAIN A,MR$TEH ; Error for host? JRST NTSN85 ; If so, abort. CAIE A,MR$TER ; Temp err for rcpt? JRST NTSN27 NTSN26: FINDA A,[A$RFCT,,[LISTAR(E)+1]] ; See if rcpt has a failure count. JRST [ MAKELN A,[A$RFCT,,[LISTAR(E)+1] ; No, make one. %LTVAL,,0] HRRM A,LISTAR(E)+1 JRST .+1] AOS A,LISTAR(A)+1 TLO F,%MSGMD ; Message LSE munged. SKIPN N ; Local host? SKIPA B,LIMRQS+1 ; Find ins for max temp failure count check. MOVE B,LIMRQS XCT B ; # temp errors greater than limit allowed? JRST [ AOS NSCTQ ; Nope, just queue. Bump cnt of # queued JRST NTSN10] ; and go back to main loop. CSTAT (,("...Giving up.")) MAKELN B,[0 %LTSAO,,[[OUTCAL(,("I gave up on sending this after "),D(A),(| "temporary" errors.|))]] ] JRST NTSN28 ; Permanent error... NTSN27: CAIE A,MR$PER ; If this was not a permanent error JSR AUTPSY ; strange type error! NTSN28: JUMPE B,NTSN29 ; Error-msg SLN may already be composed. MOVEI A,A$RRMG ; Else set up for it. DPB A,[$LAFLD,,LISTAR(B)] MOVE A,LISTAR(E)+1 HRRM A,LISTAR(B) MOVEM B,LISTAR(E)+1 ; Cons onto rcpt's list. NTSN29: AOS NSCTF ; Bump count of failures. JRST NTSN24 ; Go mark rcpt failed. ;; Here either T or R mode. Determine whether rcpt can be ;; "merged" with previous rcpt. NTSN30: SKIPE SORMSW ; Check mail/send switch... JRST [ SKIPN NSSNT1 ; Ugh!! Is this 1st rcpt this pass? JRST NTSN20 ; Yes, can just use regular default scheme! SKIPN NSRRST ; Foo, already committed, do it another pass. MOVEM E,NSRRST ; Start with this one if none yet targetted. JRST NTSN10] MOVE A,LISTAR(E)+1 CALL GNTHDR ; Get net header for rcpt MOVE A,LISTAR(A)+1 ; Get SPT for the header. CAME A,NSRHDR ; Same as current header? JRST [ SKIPN NSRHDR ; No. Is there actually any current header? JRST .+1 ; No current header, so set to this one. SKIPN NSRRST ; Sigh, headers don't match, can't send. MOVEM E,NSRRST ; Set "rcpt to restart from" for next pass. JRST NTSN10] ; Back to get another rcpt... MOVEM A,NSRHDR ; Win, set val of current header (see .+1 ref above) ;; Okay, have verified that entire msg for this rcpt is ;; identical with that of previous (if any), and can use XRCP. SKIPG XRSQS ; Skip if T mode... JRST NTSN40 ; R mode, handle differently. SKIPE NSSNT1 ; T mode. Already sent text? JRST NTSN35 ; Yes, go send rcpt name. CALL NTMINI ; No, initialize as needed JRST NTSN85 ; Ugh, abort! SETZ A, CALL NTSBEG ; Begin msg with null rcpt. JRST NTSN85 ; Assume any err means abort. SETZ A, CALL NTSMID ; Send header and text of message! JRST NTSN85 ; Assume any error means host died. CALL NTMEND JRST NTSN85 SETOM NSSNT1 ; Won, indicate text sent. ;; Here's where the rcpt name is actually sent... NTSN35: MOVE A,LISTAR(E)+1 CALL NTSXRC ; Send XRCP . JRST NTSN25 ; Error, handle just as for default case. JRST NTSN22 ; Win, also handle just as for default. ;; Rcpts-first mode! NTSN40: SKIPN NSSNT1 ; 1st part stuff done yet? JRST [ CALL NTMINI ; Nope, initialize. JRST NTSN85 ; Ugh, error means abort. JRST .+1] MOVE A,LISTAR(E)+1 CALL NTSXRC ; Send XRCP . JRST NTSN25 ; Ugh, handle error. SETOM NSSNT1 ; Indicate a rcpt was specified, MAKELN A,[0,,[NSRLST] ; and cons up a VLN to remember this rcpt %LTVAL,,[E]] ; by means of its LP. MOVEM A,NSRLST ; Gets consed onto front. JRST NTSN22 ; Then set A$RCP to A$RSNT and go get another! ;; Control comes here when main loop runs out of rcpts. ;; This doesn't necessarily mean that all rcpts for this host ;; are gone; rather, it only means that one pass of XRCP's ;; has finished. NTSN50: SKIPL XRSQS ; If R mode, lots of cleanup to do. JRST NTSN60 ; Nope, skip it. SKIPN NSSNT1 ; Were any XRCP's successfully spec'd? JRST NTSN60 ; Nope, needn't send text. SETZ A, CALL NTSBEG ; Initiate message with null rcpt. JRST NTSN55 ; Arrrrgh!!! SETZ A, CALL NTSMID ; Must send it! Output header, body, etc. JRST NTSN55 CALL NTMEND ; Terminate message text. CAIA ; Oh shit. Go handle in detail. JRST NTSN60 ; Success!! Go tidy up. NTSN55: CAIE A,MR$PEH ; Host type error? CAIN A,MR$TEH JRST NTSN85 ; Yeah, go abort stuff. CAIN A,MR$TER ; Temp err for "rcpt"? JRST NTSN85 ; Yeah, also assume abort. (easy way out) CAIE A,MR$PER ; PERM err????? Shouldn't, but... JSR AUTPSY ; (unknown result code) ; Perm fail: set all RCP's on NSRLST to RCPF's. SKIPN A,NSRLST JRST NTSN60 ; None to flush?? Oh well. MOVE C,B ; Put error message SLP in C as arg. MOVEI B,A$RRMG DPB B,[$LAFLD,,LISTAR(C)] ; Set up with proper attrib. MOVEI B,[MOVE A,LISTAR(A)+1 LDB C,[$LAFLD,,LISTAR(A)] CAIE C,A$RSNT PJRST POPJ1 MOVEI C,A$RCPF DPB C,[$LAFLD,,LISTAR(A)] SOS NSCTS LNCOPY B,[0 ? B] ; Get a SLN for err msg. MOVE C,LISTAR(A)+1 ; Cons onto HRRM C,LISTAR(B) ; start of MOVEM B,LISTAR(A)+1 ; rcpt's list. TLO F,%MSGMD PJRST POPJ1] CALL MAPC JSR AUTPSY NTSN60: SKIPE NSRLST LNDEL NSRLST ; Delete everything in the temporary list... SKIPN E,NSRRST ; Any need to restart a pass? JRST NTSN95 ; Take win return. SETZM NSRHDR ; New pass needed, LP to 1st is now in E. SETZM NSSNT1 ; Clear necessary stuff. SETZM NSRRST ; e.g. the restart indicator! JRST NTSN11 ; Re-enter loop at right place. ; Handle abort caused by host failure. NTSN80: IFN 0,[ ;; I tried putting Chaos SENDs in the "init" phase one day... SKIPN SORMSW ; Sends require some cleanup. JRST NTSN85 SKIPE XRSQS ; Treat XRCPd sends like mail. JRST NTSN85 ;; Here to abort a failing send. MOVE C,B ; Put error message SLP in C as arg. MOVEI B,A$RRMG ; Set up with proper attrib. DPB B,[$LAFLD,,LISTAR(C)] MOVE A,LISTAR(A)+1 ; LP to rcpt list. MOVEI C,A$RCPF ; Say we are a failure. DPB C,[$LAFLD,,LISTAR(A)] LNCOPY B,[0 ? B] ; Get a SLN for err msg. MOVE C,LISTAR(A)+1 ; Cons onto HRRM C,LISTAR(B) ; start of rcpt's list. MOVEM B,LISTAR(A)+1 AOS NSCTF ; Count a failure. TLO F,%MSGMD POPAE P,[L,E,D,C,B,A] JRST POPJ1 ];IFN 0 NTSN85: SKIPGE XRSQS ; Only R mode requires any backing up, SKIPN NSRLST ; and only when a "sent" list exists. JRST NTSN99 ; Others just take non-skip return. ;; Change all A$RSNT's on temp list to A$RCP's again. ;; Don't bother trying to hack rcpt failure counts now. Maybe someday ;; the failure stuff will be modularized enough to make it plausible. MOVE A,NSRLST MOVEI B,[MOVE A,LISTAR(A)+1 LDB B,[$LAFLD,,LISTAR(A)] CAIE B,A$RSNT PJRST POPJ1 SOS NSCTS ; Bump down cnt of # sent. MOVEI B,A$RCP DPB B,[$LAFLD,,LISTAR(A)] PJRST POPJ1] CALL MAPC JSR AUTPSY JRST NTSN99 ; Abort, so take non-skip return. NTSN95: AOSA -6(P) NTSN99: AOS NSCTQ ; Failure return always wants queueing. POPAE P,[L,E,D,C,B,A] RET SUBTTL NSRFND, NSRNAM, GNTHDR ; NSRFND - Find a valid recipient. ; A - LP to start searching from. ; N - host # that rcpt must be for. ; Returns .+1 if none found. ; Returns .+2 ; A - LP to A$RCP that fits this host. NSRFND: PUSH P,B NSRFN0: FINDA A,[A$RCP,,[A]] ; Hunt for an active rcpt PJRST POPBJ FINDA B,[A$RPSN,,[LISTAR(A)+1]] ; Is rcpt a pseudo? CAIA JRST NSRFN5 ; Yeah, get next. FINDA B,[A$RHST,,[LISTAR(A)+1]] ; Get host... TDZA B,B MOVE B,LISTAR(B)+1 ; Get host # CAMN B,OWNHS2 SETZ B, CAMN B,OWNHST ; Canonicalize self. SETZ B, CAMN B,N ; Right host? PJRST POPBJ1 ; Yep, win return. NSRFN5: HRRZ A,LISTAR(A) ; Sigh, try another. JUMPN A,NSRFN0 PJRST POPBJ ; NSRNAM - Get name for rcpt. ; A - LP to rcpt list. ; Returns ; A - SLP to string to use in FTP command. ; If sign bit set, SLN should be deleted after using. ; NSRNAM: PUSH P,A ; Save LP to rcpt list FINDA A,[A$RTYP,,[A]] ; See if any explicit type spec. JRST NSRNM1 ; Nope, can just use name. SLNEA A,[ASCNT [NAME]] ; Type NAME? JRST [ POP P,A ; Sigh, something hairy. Invoke full routine. MAKELN A,[0 ? %LTSAO,,[[CALL NSRNMO]]] RET] NSRNM1: POP P,A FINDA A,[A$RNAM,,[A]] ; Regular name, get it. No further checking. JSR AUTPSY RET ; NSRNMO - Outputs structured recipient name on standard output. ; A/ LP to rcpt list ; Clobbers nothing. NSRNMO: PUSH P,B FINDA B,[A$RTYP,,[A]] ; See if any explicit type spec. JRST NSRNM2 ; Nope, can just use name. SLNEA B,[ASCNT [NAME]] ; Type NAME? JRST NSRNM3 ; Sigh, something hairy. NSRNM2: FINDA B,[A$RNAM,,[A]] ; Regular name, get it. JSR AUTPSY OUT(,SL(B)) JRST NSRNM9 NSRNM3: SLNEA B,[ASCNT [*MSG]] ; Type *MSG? CAIA ; No, thank goodness. JRST [PUSHJ P,BBDDFS ; Get filename for *MSG. OUT(,LBRK,6Q(LMFDIR),(";"),6Q(LMFFN1),(" "),6Q(LMFFN2),RBRK) JRST NSRNM9] PUSH P,C ; Basic default is to use structured syntax. FINDA C,[A$RNAM,,[A]] JSR AUTPSY OUT(,LPAR,SL(B),(" "),SL(C),RPAR) POP P,C NSRNM9: POP P,B RET ; GNTHDR - Get SLP to net header to use for rcpt. ; A - LP to rcpt's list ; Returns ; A - SLP to header to use. GNTHDR: FINDA A,[A$RHDR,,[A]] ; First try rcpt header... CAIA RET ; Win! MOVE A,N ; No rcpt header, is rcpt at ITS site? CALL NHITS ; See if ITS FINDA A,[A$KHDR,,[$LLLST(L)]] ; No, is there a kludge header? CAIA ; ITS, or no kludge header... RET ; Not ITS, and kludge header exists, use it. FINDA A,[A$MHDR,,[$LLLST(L)]] ;Use the default header JSR AUTPSY RET SUBTTL NTSBEG, NTSXRC,NTSMID ; NTSBEG - Setup to begin message transmission. ; A - LP to a rcpt list ; If zero, assumes no rcpt, just sets up for msg text. ; This is used by XRCP scheme hacking. ; Returns .+1 if failure (err code in A, string in B) ; Returns .+2 if success. NTSBEG: STAT (,TAB) ; New line, tab out. PUSH P,C SETZ B, ; Remember if we are Mailing. FINDA C,[A$MTXT,,[$LLLST(L)]] JSR AUTPSY HLRZ C,LISTAR(C)+1 CAML C,NSMFLN SETO B, ; For long message, use MLFL. SKIPE SORMSW ; If we are Sending instead of Mailing MOVEI B,1 ; Remember so. ;; If just initiating text, skip name hackery. JUMPE A,[ CSTAT (,("TEXT-"),RABR) JRST NTSBG4] CALL NSRNAM ; Now get a SLP to name we'll give to host. MOVE C,A ; Save it. MOVE A,LISTAR(A)+1 ; Make an ADD A,$LSLOC(L) ; ASCNT ptr out of it. CSTAT (,("TO-"),RABR,TC(A)) NTSBG4: CALL NTMBEG ; Invoke!! CAIA AOS -1(P) ; Won, skip on return. CAIGE C, LNDEL C, ; Flush temp SLN if need to. POP P,C RET ; NTSXRC - Specify a recipient via XRCP. ; A - LP to rcpt's list ; Skips if won, message results in A, B. NTSXRC: PUSH P,C CALL NSRNAM ; Now get a SLP to name we'll give to host. MOVE C,A ; Save it. MOVE A,LISTAR(A)+1 ; Make an ADD A,$LSLOC(L) ; ASCNT ptr out of it. STAT (,(" XTO-"),RABR,TC(A)) ; New line, tab out, special to... CALL NTXRCP ; Invoke XRCP... CAIA AOS -1(P) ; Won, skip on return. CAIGE C, LNDEL C, ; Flush temp SLN if need to. POP P,C RET ; NTSMID - Send middle stuff (actual text). ; A - LP to rcpt's list. If zero, uses NSRHDR for header. ; Returns .+1 if failure (net error type) ; Returns .+2 if won. NTSMID: JUMPE A,[SKIPN A,NSRHDR JSR AUTPSY JRST NTSMD3] PUSHJ P,GNTHDR ; Get SLP to header in A MOVE A,LISTAR(A)+1 NTSMD3: ADD A,$LSLOC(L) PUSHJ P,NTMSND ; Send out over net! RET ; error.... FINDA A,[A$MTXT,,[$LLLST(L)]] ; Now send text. JSR AUTPSY MOVE A,LISTAR(A)+1 ADD A,$LSLOC(L) PUSHJ P,NTMSND RET ; error.... SETZB A,B AOS (P) RET