Title VMAIL - MMAILR / TOPS-20 Mail-11 Listener Subttl LCampbell/GStevens/DDyer-Bennet/MDLyons/JHTorrey/PLBudne/MRCrispin Search Macsym,Monsym .require Sys:Macrel Sall .directive Flblst .text "/NOINITIAL" .text "VMAIL/SAVE" IFNDEF OT%822,OT%822==:1 ; This program is derived from the VMAIL distributed on the ; "integration tools tape". It listens on DECnet object 27 for mail ; from the VMS MAIL Utility. When a VMS user says "MAIL NODE::USER" A ; connection is established then and there, and text is sent one line ; at a time. A problem is that this server is single thread, and one ; VMS user can tie up the port, making all other mail to the '20 ; fail!! ; At the current time the addressee must be a valid TOPS-20 username, ; since the destination is stored as a user number. I never finished ; an interface to MMAILBOX to vaildate full MMAILR addresses. ; Another interesting problem is that there may be no reply path for ; mail. I had thought of taking the VMAILR program and hacking it to ; be the delivery agent for a #Special domain. At BU we run software ; tools mail on most VMS systems, so this is not a problem. IFNDEF FTRCVD,FTRCVD==1 ;INCLUDE RECIEVED: HEADER IFNDEF MBXF,MBXF==0 ;INCOMPLETE!! IFN MBXF,< .REQUIRE VMAMBX ;INTERFACE TO MMAILBOX EXTERNAL MBXFRK,MBXVFY > ;MBXF T1==1 T2==2 T3==3 T4==4 T5==5 P1==6 P2==7 P3==10 P4==11 P5==12 Ptr==13 ;Global Byte Pointer To Receive Mail Cnt==14 ;Global Byte Count For Same Cx==16 P==17 .ver==6 .mvr==1 .edt==^D82 Loc 137 Exp <.ver>B11+<.mvr>B17+1B18+.edt Reloc Define Jerr(String),< Xlist IFJER. Hrroi T1,[Asciz /VMAIL error: /] Esout Hrroi T1,[Asciz /String/] Psout Hrroi T1,[Asciz / because: /] Psout Movx T1,.priou Hrloi T2,.fhslf Erstr Erjmp .+2 Erjmp .+1 Call Dtstmp ;; Log This Lossage Also Log Log < Because: > Move T1,LogJFN Hrloi T2,.fhslf Erstr Erjmp .+2 Erjmp .+1 Jrst Fatal ENDIF. List > Define Log(String),< ;; Put Message Into Log File Xlist Hrroi T1,[Asciz \String\] ;; So It Can Type Slashes Call Logmsg List > Define Debug(String),< Skipn Dbugsw IFSKP. Hrroi T1,[Asciz /String/] Psout ENDIF. > Define Debstr(String),< Skipn Dbugsw IFSKP. Hrroi T1,String Psout ENDIF. > Define Clrbuf(bufnam,Buflen),< Setzm Bufnam Move T1,[Bufnam,,Bufnam+1] Blt T1,Bufnam+buflen-1 > Define Nchar,< Move T1,NetJFN Bin Move T1,T2 > Define Nrecord(Buffer,Nchar),< Move T1,NetJFN Hrroi T2,Buffer Movni T3,Nchar Setz T4, Sinr Jerr > Define Vaxsuccess,< Move T1,NetJFN Hrroi T2,[Ascii//] Movei T3,-4 Setz T4, Soutr > Define Vaxerr(Errmsg),< Move T1,NetJFN Hrroi T2,[Ascii//] Movei T3,-4 Setz T4, Soutr Move T1,NetJFN Hrroi T2,[Asciz /Errmsg/] Setzb T3,T4 Sout Hrroi T2,Atmbuf Setzb T3,T4 Sout Hrroi T2,[Asciz/ At Node /] Setzb T3,T4 Sout Hrroi T2,ournam Setzb T3,T4 Soutr ; force string transmission Hrroi T2,[0] Movei T3,-1 Setz T4, Soutr > Define Die(String),< ;; Fatal Internal Error Xlist Jrst [ Hrroi T1,[Asciz /VMAIL fatal internal error: /] Esout Hrroi T1,[Asciz /String/] Psout Hrroi T1,[Asciz / /] Psout Call Dtstmp ;; Time Stamp It Hrroi T1,[Asciz /Fatal error: /] Call Logmsg Hrroi T1,[Asciz /String/] Call Logmsg Jrst Fatal] List > Define Herald(Ver,Edt),< Xlist ; Tmsg Hrroi T1,[Asciz /VMAIL version Ver(Edt) running/] Call Logmsg List > Define Log(String),< Xlist Hrroi T1,[Asciz \String\] Call Logmsg List > ;Storage Tmplen==500 ; Temporary Storage Natmbf==100 ; Length Of Atom Buffer In Words Bbflen==300000 ;[154] Length Of Big Mail Buffer Nfrmbf==70 ; Length Of Sender Name Buffer Timen==^D<10*60*1000> ; Milliseconds Before Sender Declared Tardy Stklen==200 ; Size Of Stack Dbugsw: 0 ; -1 If Debug Atmbuf: Block Natmbf ; Atom Buffer Subbuf: Block Natmbf ; Subject Buffer Toocnt: Block 1 ; Count of recipients per line in TOOBUF Tooptr: Block 1 ; Pointer to current position in TOOBUF Toobuf: Block Natmbf ; To Names Buffer Bigbuf: Block Bbflen ; Where It All Is Combined To Nodstr: Block ^D200 ; String space for recipient nodes/USERS NODPTR: BLOCK 1 ;[BUDD] BP INTO NODSTR Ulist: Block ^D200 ; Where To Store Mailbox Directory Numbers Frmbuf: Block Nfrmbf ; Where To Put Sender'S Name Plus Host Frmnam: Block Nfrmbf ; Where To Put Sender'S Name Ournam: Block 2 ; Our Host Name Hstnam: Block 2 ; Host name we are sending to Usrnum: Block 1 ; User number we are sending to MYPID: BLOCK 1 ;[BUDD] OUR IPCF PID BUFFER: BLOCK 10 ;[BUDD] IPCF BUFFER IPCBLK: BLOCK 4 ;[BUDD] IPCF DESCR BLOCK OURJOB: BLOCK 1 ;[BUDD] OUR JOB NUMBER QUEJFN: BLOCK 1 ;[BUDD] MMAILR QUEUE JFN Filnam: Block 1 ;[BUDD] File name for MMAILR QUEUE FILE Temp1: Block Tmplen Temp2: Block Tmplen Stack: Block Stklen ; One Stack For Each Fork NetJFN: Block 1 ; Network File JFN LogJFN: Block 1 ; Log File JFN LOGP: BLOCK 1 ; Non-zero if keeping logs Ntime: Block 1 ; Time Receipt Of Mail Initiated (For Status) Elptim: Block 1 ; Elapsed Time For Receipt Of Mail Kepliv: Block 1 ; Keep alive count for dead mans timer Bytcnt: Block 1 ; Length Of Mail In Bytes Capenb: Block 1 ; Saved Capabilities IFN MBXF,< ;[BUDD] GOTMBX: BLOCK 1 ;[BUDD] -1 IF HAVE MBX FORK > ;[BUDD] MBX Pc1: Block 1 ; Pc Save Location For Psi Level Pc2: Block 1 Pc3: Block 1 Levtab: Pc1 Pc2 Pc3 Chntab: 2,,Conect ; Connect Initiate On Level 2 1,,Timout ; Timeout Psi On Level 1 Xlist ; Nothing Else Repeat ^d34, List VMAIL:: Reset Move P,[-Stklen,,Stack] GJINF ;[BUDD] Movem T3,OurJob ;[BUDD] Movx T1,.ndgln ; Get Local Node Name Function Move T2,[Point 7,Ournam] Movem T2,1(P) ; Put Pointer On Stack Movei T2,1(P) ; And Point To It Node ; Get Node Name ifjer. tmsg haltf% endif. IFN MBXF,SETZM GOTMBX ;[BUDD] CLEAR MBX AVAIL FLAG Movx T1,.fhslf ; This Process Move T2,[Levtab,,Chntab] Sir ; Init Psi System Eir Call Opnlog ; Open Log File Movem T1,LogJFN ; Save JFN Call Dtstmp ; Time Stamp It Herald \.ver,\.edt Log< on node > ; Tmsg < on node > ; Hrroi T1,Ournam ; Psout ; Tmsg < ;> Hrroi T1,Ournam Call Logmsg VMAIL0: Call Opnlsn ; Open Connection And Set Interrupt Up Move T1,LogJFN ; Close Log File For Perusers Closf Erjmp .+1 Wait ; For Connect Initiate ;Here When Connection Initiated Conect: Move P,[-Stklen,,Stack] ; Reset Stack Call Timeit ; Time This Guy Call Opnlog ; Open Log File Movem T1,LogJFN Call Dtstmp ; Time Stamp This Transaction Log <----Connect from > Debug <----Connect from > Call T4nhst ; Type Foreign Host Name At Log File Clrbuf Subbuf,Natmbf Move T1,NetJFN ; Accept Connection Movx T2,.mocc Setzb T3,T4 ; No Additional Data Mtopr Jerr Conct1: Move T1,NetJFN ; Get network link status Movei T2,.morls Mtopr Jerr TXNE T3,MO%ABT ; [154] Has the link been aborted? JRST DMPLNK ; [154] Yes, get rid of it. Txne T3,Mo%con ; Skip if link not connected Jrst Conct2 Movei T1,^D1000 ; Wait a second and try again Disms Jrst Conct1 Conct2: Movx T1,.hpelp ; Elapsed Time Since System Startup Hptim ; Snarf It Jerr Movem T1,Ntime ; Remember Time This Reception Started Call Parse ; Parse The Mail Jrst Errxit ; Failed, Quit Now Call Dtstmp ; Time Stamp Log Log Hrroi T1,Frmbuf ; Sender'S Name Call Logmsg ; Log It Log < received > Call Lstats ; Log Statistics Call Mailit ; Send The Mail Off Die Errxit: Call Clznet ; Close And Reopen Net Link Call Cncltm ; Cancel Timeout Request Call Dtstmp Log <----Connection closed> Move T1,LogJFN Closf ; Close Log File For Perusers Erjmp .+1 Debrk ; Return To Background ; Parse Mail Received. Place Sender Name In Frmbuf, Recipient Directory ; Numbers In Ulist, Terminated With A Zero Entry ; Headers Must Appear In The Following Order. ; From, To, Cc ; Returns +1: Failure ; +2: Success ; ;PROGRAM FLOW DESCRIPTION NOT ALL ITEMS IN FLOW ARE IN THIS ROUTINE BUT ;IT DOES REPRESENT THE PROCEDURE TO SEND TO A VAX WHICH IS WHY IT IS ;INCLUDED HERE ; ; RECEIVE FROM FIELD FROM VAX ; PARSE FROM FIELD CONVERTING IT TO MS TYPE FIELD IN FRMBUF ; REPEAT UNTIL NULL RECEIVED ; : RECEIVE A RECIPIENT NAME FOR VERIFICATION ; : IF NULL RECEIVED ; : : THEN ; : : : EXIT REPEAT LOOP ; : ENDIF ; : PARSE USER NAME AND NODE ; : IF NODE SAME AS THIS NODE ; : : THEN ; : : : IF USER IS ON THIS SYSTEM ; : : : : THEN ; : : : : : SEND SUCCESS CODE TO VAX ; : : : : : PUT USER NUMBER INTO ULIST ; : : : : ELSE ; : : : : : SEND FAILURE CODE TO VAX ; : : : : : SEND ERROR MESSAGE TO VAX ; : : : : : SEND NULL TERMINATING ERROR MESSAGE TO VAX ; : : : : : RETURN FROM ROUTINE ; : : : ENDIF ; : : ELSE ; : : : SEND SUCCESS TO VAX (MESSAGE WILL BE QUEUED) ; : : : PUT -1 INTO ULIST ; : : : PUT NODE NAME INTO NODLST ; : ENDIF ; END REPEAT ; RECEIVE TO FIELD FROM VAX ; PARSE TO FIELD CONVERTING IT TO MS TYPE FIELD IN TOOBUF ; RECEIVE SUBJECT FIELD FROM VAX ; BEGIN FORMATING MESSAGE INTO MS TYPE MESSAGE ; REPEAT UNTIL NULL RECEIVED ; : RECEIVE A LINE FROM VAX ; : IF NULL RECEIVED ; : : THEN ; : : : EXIT REPEAT LOOP ; : ENDIF ; : OUTPUT TO MS MESSAGE BUFFER ; END REPEAT ; REPEAT UNTIL NULL DETECTED ; : GET FIRST ITEM IN ULIST ; : IF FIRST ITEM IN ULIST = -1 ; : : THEN ; : : : GET NODE FROM NODLST ; : : : PUT MAIL INTO FILE FOR DMAILR ; : : : SET FLAG IN DECNET-FLAGS SO FILE GETS SENT ; : : ELSE ; : : : PUT MAIL INTO USERS MAIL FILE ; : : : SPLAT OBNOXIOUS MESSAGE ACCRESS USERS SCREEN ; : ENDIF ; : IF NO ERROR ; : : THEN ; : : : SEND POSITIVE ACKNOWLEDGEMENT TO VAX ; : : ELSE ; : : : SEND NEGATIVE ACKNOWLEDGEMENT TO VAX ; : : : SEND ERROR MESSAGE TO VAX ; : : : SEND NULL TERMINATOR TO VAX ; : ENDIF ; END REPEAT ; RETURN +2 Parse: Clrbuf Frmnam,Nfrmbf Move T1,NetJFN ; Save It Movei T2,.morss ; Read Max Record Size Mtopr Jerr ; This could fail... Nrecord , ; Read From Field Hrroi T1,Temp1 ; Setup Default Host Hrroi T2,Hstnam Setzb T3,T4 Sout Hrroi T1,Frmbuf ;Parse from field, results to FRMBUF Move T2,[Point 7,Frmnam] Call Prsnam Setzm Toobuf ; Clear first location of TOOBUF Hrroi T1,Toobuf ; Setup pointer to TOOBUF Movem T1,Tooptr Movei T1,3 ; Setup count of recipients per line in TOOBUF Movem T1,Toocnt MOVEI T1,NODSTR ;[BUDD] Movem T1,NodPTR ;[BUDD] Movsi P1,-^D100 ; Maximum Of 100 Names In List Parse3: Clrbuf Atmbuf,Natmbf ; Clear receive area Nrecord , ; Receive recipient from VAX Aos Kepliv ; Increment keep alive count Skipn Atmbuf ; Skip if not end of list Jrst Parse6 ; End of recipient list Call Prsusr ; Parse recipient Jrst [ Call Dtstmp ; None Found, Complain Vaxerr <%Network mail error: No such user > Log <%Network mail error: No such user > Hrroi T1,Atmbuf ; Also Log Losing Name CallRet Logmsg] Movem T1,Ulist(P1) ; Save number returned for mailing Vaxsuccess ; Send VAX the success code Aobjn P1,Parse3 ; Jump if not too many recipients Call Dtstmp ; Woops, Too Many Hrroi T1,Atmbuf ; Also Tell Log File CallRet Logmsg Parse6: Setzm Ulist(P1) ; Tie Off Recipient List ; ; Now Get Mailed To Field With Node Name And Subject ; Clrbuf Atmbuf,Natmbf Nrecord , Nrecord , ; Now Conbine It All Into Bigbuf Setzm Bytcnt Hrroi T1,Bigbuf IFN FTRCVD,< ;[BUDD] Hrroi T2,[Asciz /Received: from /] ;[BUDD] now, write Received line Setz T3, ;[BUDD] SOUT ;[BUDD] Hrroi T2,HSTNAM ;[BUDD] SOUT ;[BUDD] HRROI T2,[ASCIZ ' by '] ;[BUDD] SOUT ;[BUDD] HRROI T2,OURNAM ;[BUDD] SOUT ;[BUDD] Hrroi T2,[Asciz ' using MAIL-11 '] ;[BUDD] SOUT ;[BUDD] Seto T2, ;[BUDD] output current date/time MovX T3,OT%DAY!OT%SPA!OT%TMZ!OT%SCL!OT%822 ODTIM ;[BUDD] RFC 822 standard date JERR ;[BUDD] Hrroi T2,CRLF0 ;[BUDD] Setz T3, ;[BUDD] SOUT ;[BUDD] > ;IFN FTRCVD Hrroi T2,[Asciz /Date: /] Setz T3, Sout Seto T2, MovX T3,OT%DAY!OT%SPA!OT%TMZ!OT%SCL!OT%822 Odtim Jerr Hrroi T2,[Asciz/ From: /] Setz T3, Sout Hrroi T2,Frmbuf Setz T3, Sout Hrroi T2,[Asciz/ To: /] Setzb T3,T4 Sout Hrroi T2,Toobuf Setzb T3,T4 Sout Hrroi T2,[Asciz/ Subject: /] Setzb T3,T4 Sout Hrroi T2,Subbuf Setzb T3,T4 Sout Hrroi T2,[Asciz/ Mailed-to: /] ;[BUDD] Setzb T3,T4 Sout Hrroi T2,Atmbuf Setz T3, Sout Hrroi T2,CRLF0 SOUT Hrroi T2,CRLF0 SOUT Move T5,T1 Repeat: Clrbuf Temp1,Tmplen ; Clear storage area Nrecord , ; Get a message line from the VAX Aos Kepliv ; Increment keep alive count Camn T3,[-] ; Blank line ? Jrst Crlf ; Yes, output CRLF Skipn Temp1 ; End of message ? Jrst Done ; Yes Move T1,T5 ; Output message line to BIGBUF Hrroi T2,Temp1 Setzb T3,T4 Sout Jerr ; [151] Add error check Move T5,T1 Crlf: Move T1,T5 ; Output CRLF to BIGBUF Hrroi T2,[Asciz/ /] Setzb T3,T4 Sout Jerr ;[152] Add error check Move T5,T1 Jrst Repeat Done: Move T1,T5 ; Close off message Hrroi T2,[Asciz / /] Setzb T3,T4 Sout Call Gtbfsz ; Get Buffer Size Into Bigbug Debug < > Debstr Retskp ; All Done! ; ;Store Size Of Bigbuf Into Bytcnt ; Gtbfsz: Setz T3, Setz T2, Move T1,[Point 7,Bigbuf] Geta: Ildb T2,T1 Jumpe T2,Go Addi T3,1 Jrst Geta Go: Movem T3,Bytcnt Jrst R ;Routine to parse a node and user name and convert it to a TOPS-20 ;string compatable with MS ; ;CALL: ; T1 = STRING POINTER TO THE DESTINATION ; T2 = STRING POINTER TO FIELD RECEIVED ; CALL PRSNAM ; ;VARIABLES RETURNED ON SUCCESSFUL COMPLETION ; DESTINATION CONTAINS THE MS STRING ; TEMP1 = HOST ; TEMP2 = USER NAME ; T1 = UPDATED STRING POINTER ; ;RETURNS: ; +1 ALWAYS PRSNAM: ACVAR ; STORAGE FOR SOURCE/DEST. POINTERS MOVEM T1,DPTR ; SAVE DESTINATION POINTER MOVEM T2,SPTR ; SAVE SOURCE POINTER PRSNM1: MOVE T1,[POINT 7,TEMP2] ; GET POINTER TO WHERE TO STORE STRING PRSNM2: ILDB T3,SPTR ; GET CHARACTER JUMPE T3,PRSNMD ; NULL, DONE CAIN T3," " ; SPACE SEPARATOR? JRST PRSNM3 ; YES, LOOK FOR PERSONAL NAME CAIE T3,":" ; END OF NODE SPECIFIER? IFSKP. ILDB T3,SPTR ; YES, EAT NEXT COLON SETZ T3, ; TERMINATE STRING IDPB T3,T1 HRROI T1,TEMP1 ; UPDATE ORIGINATING HOST HRROI T2,TEMP2 SOUT JRST PRSNM1 ENDIF. IDPB T3,T1 ; SAVE CHARACTER IN TEMP2 JRST PRSNM2 PRSNM3: SETZ T3, ; TERMINATE STRING IDPB T3,T1 PRSNM4: ILDB T3,SPTR ; GET CHARACTER FROM INPUT STRING JUMPE T3,PRSNMD ; STRING EXHAUSTED CAIE T3,42 ; IS CHARACTER START OF PERSONAL NAME? JRST PRSNM4 ; NO, LOOP TILL STRING EXHAUSTED OR '"' FOUND MOVE T1,DPTR ; GET DESTINATION POINTER MOVE T2,SPTR ; GET SOURCE POINTER SETZ T3, MOVEI T4,42 ; TILL '"' SOUT MOVEI T2," " ; CHANGE '"' TO SPACE DPB T2,T1 MOVEI T2,"<" ; OUTPUT START OF USERNAME at NODE STRING IDPB T2,T1 CALL PRSNMS ; CALL ROUTINE TO OUTPUT USERNAME at NODE MOVEI T2,">" ; OUTPUT END OF USERNAME at NODE STRING IDPB T2,T1 SETZ T2, ; TERMINATE THE OUTPUT STRING IDPB T2,T1 RET ; SUCCESS RETURN PRSNMD: IDPB T3,T1 ; TERMINATE STRING MOVE T1,DPTR ; BUILD STRING IN DESTINATION BUFFER CALLRET PRSNMS ENDAV. ;Routine to create user name at node string in output buffer. ; ;CALL: ; T1 = STRING POINTER TO WHERE TO STORE THE OUTPUT ; TEMP2 = USER NAME ; TEMP1 = NODE NAME ; CALL PRSNMS ; ;VARIABLES RETURNED: ; T1 = UPDATED STRING POINTER ; ;RETURNS: ; +1 ALWAYS PRSNMS: HRROI T2,TEMP2 ; OUTPUT USER NAME SETZB T3,T4 SOUT ;; HRROI T2,[ASCIZ/ at /] ; OUTPUT SEPARATOR ;; SOUT MOVEI T2,"@" BOUT HRROI T2,TEMP1 ; OUTPUT NODE NAME SOUT HRROI T2,[asciz/.#DECnet/] SOUT RET ; SUCCESS RETURN ;Routine to parse addressing of VAX mail and build TO string in TOOBUF ; ;CALL: ; ATMBUF = ADDRESS STRING RECEIVED FROM THE VAX ; CALL PRSUSR ; ;VARIABLES RETURNED ON SUCCESS: ; TEMP1 = NODE OF RECIPIENT ; TEMP2 = NAME OF RECIPIENT ; T1 = USER NUMBER IF ON CURRENT NODE OR ; PTR TO NODE // '\0' // USER FOR 4N HOST ; ;RETURNS: ; +1: ERROR, MAIL WAS ADDRESSED TO THIS NODE AND USER WAS UNKNOWN ; +2: OK, ALL RETURNED VARIABLES VALID PRSUSR: MOVE T1,TOOPTR ; GET POINTER TO TOOBUF SKIPN TOOBUF ; SKIP IF TOOBUF NOT EMPTY JRST PRSUS1 SOSE TOOCNT ; SUBTRACT FROM COUNT/LINE - SKIP IF .NE. 0 IFSKP. HRROI T2,[BYTE (7) ",", "M"-100, "J"-100, "I"-100] SETZ T3, SOUT MOVEI T2,3 ; RESET COUNT OF USERS PER LINE IN TOOBUF MOVEM T2,TOOCNT JRST PRSUS1 ENDIF. HRROI T2,[ASCIZ/, /] ; OUTPUT SEPARATOR SETZ T3, SOUT PRSUS1: MOVEM T1,TOOPTR ; SAVE STRING DESTINATION POINTER HRROI T1,TEMP1 ; SETUP DEFAULT HOST HRROI T2,OURNAM SETZ T3, SOUT MOVE T1,TOOPTR ; GET DESTINATION POINTER MOVE T2,[POINT 7,ATMBUF] ; GET POINTER IN INPUT STRING CALL PRSNAM ; GET TOPS-20 MS STRING MOVEM T1,TOOPTR ; SAVE POINTER TO TOOBUF HRROI T1,OURNAM ; GET POINTER TO THIS SYSTEMS NODE NAME HRROI T2,TEMP1 ; GET HOST NAME FROM FIELD STCMP ; IS MESSAGE FOR THIS HOST ? JUMPE T1,PRSUS2 ; JUMP IF FOR THIS HOST ;MAIL IS FOR A REMOTE HOST. GET HOST,,USER STRING POINTERS HRRZ T4,NODPTR ;GET POINTER TO STRING SPACE HRRO T1,T4 ;PUT NODE NAME INTO NODE STRING SPACE HRROI T2,TEMP1 SETZ T3, SOUT IDPB T3,T1 ;GET TERMINATOR HRROI T2,TEMP2 ;GET USER SOUT IDPB T3,T1 HRRZM T1,NODPTR MOVE T1,T4 ;GET STRING POINTER RETSKP ; RETURN ADDRESS ;MAIL IS FOR THIS SYSTEM. CHECK TO SEE IF USER NAME IS VALID. PRSUS2: IFE MBXF,< HRROI T2,TEMP2 ; POINT TO USER NAME STRING MOVX T1,RC%EMO ; EXACT MATCH ONLY RCUSR ; IS THIS USER NAME VALID ? ERJMP R ; NO, ERROR TXNE T1,RC%NOM ; SKIP IF USERNAME FOUND RET ; NO SUCH USER - ERROR MOVE T1,T3 ; RETURN USER NUMBER IN T1 > ;IFE MBXF IFN MBXF,< PRINTX NEED CODE AT PRSUS2 > ;IFN MBXF RETSKP ; RETURN SUCCESS ; Here To create MMAILR queue file ; Returns +1: Problems Of Some Sort ; +2: Ok Mailit: Hrroi T1,FILNAM Hrroi T2,[Asciz 'MAILQ:[--QUEUED-MAIL--].NEW-'] Setz T3, SOUT Move T2,T1 GTAD Exch T1,T2 Movei T3,10 NOUT Trn Hrroi T2,[Asciz '-VMAIL-J'] Setz T3, SOUT Move T2,OURJOB Move T3,[3,,^D10] NOUT Trn Hrroi T2,[Asciz '.-1;P770000'] Setz T3, SOUT Idpb T2,T3 Movsi T1,(GJ%SHT+GJ%FOU) Hrroi T2,FILNAM GTJFN JERR Movem T1,QUEJFN Move T2,[fld(7,OF%BSZ)+OF%WR] OPENF JERR Hrroi T2,[Asciz ' =NET-MAIL-FROM-HOST:'] Setz T3, SOUT Hrroi T2,HstNam SOUT Hrroi T2,CRLF0 SOUT Hrroi T2,[Asciz ' =RETURN-PATH:'] SOUT Hrroi T2,FRMBUF SOUT Hrroi T2,CRLF0 SOUT ;; This is not documented -- but it makes MMAILR splat your TTY right! Hrroi T2,[Asciz ' _'] SOUT Hrroi T2,HstNam SOUT Hrroi T2,[ASCIZ/.#DECnet /] SOUT Move T3,[Point 7,FrmNam] DO. Ildb T2,T3 Jumpe T2,ENDLP. Cain T2," " EXIT. BOUT LOOP. OD. Hrroi T2,CRLF0 Setz T3, SOUT Setzb P1,P2 ; Init Index And Failure Flag Mailt1: Move T1,Ulist(P1) ; Get Next Recipient Jumpe T1,Mailt5 ; End Of List Call Sendit ; ADD NAME TO TOP OF QUEUE FILE TRN Mailt2: Vaxsuccess Aoja P1,Mailt1 Mailt5: Jumpn P2, Rskp ; Don'T Log Success on error ;; Skipe P1 ; Anything Sent? ;; IFSKP. ;; Call Dtstmp ; Yes, Loc Lack Of Local Users ;; Log ;; ENDIF. Move T1,QUEJFN ; Get MMAILR queue JFN ;;[76] Hrroi T2,CRLF0 ;;[76] Setz T3, ;;[76] SOUT ;Sendit now has been fixed!! Movei T2,"L"-100 BOUT Hrroi T2,CRLF0 SOUT Move T2,[Point 7,Bigbuf] ; Shove message into queue file Movn T3,Bytcnt ; Get negative byte count SOUT Erjmp .+1 CLOSF TRN CALL WAKEUP Retskp ; Append Mail To User'S Mail File ; Call With User Number Of Recipient In T1 Sendit: Stkvar Movem T1,Usrno ; Save Recipients User Number Jumpg T1,Quefil ; 4n host Move T1,QueJFN ; Get QUEUE file Movei T2,"L"-100 ; Get BOUT Hrroi T2,OurNam Setz T3, SOUT Hrroi T2,CRLF0 SOUT Move T2,UsrNo DIRST ERJMP .+1 ;[76] DIRST% always gives +1 return Hrroi T2,CRLF0 SOUT Retskp ;Sending to a remote host. Quefil: MOVE T1,QUEJFN MOVEI T2,"L"-100 BOUT HRRO T2,USRNO ;GET HOST BP SETZ T3, SOUT MOVEM T2,USRNO ;SAVE BP TO USER HRROI T2,CRLF0 SOUT MOVE T2,USRNO ;GET USER BP SOUT HRROI T2,CRLF0 SOUT RETSKP ;all done ;Here to copy (and quote) "from" string into area pointed to by T1 ; Quotes all characters (to save trouble of checking need for it) QUOTE: MOVE T2,[POINT 7,FRMBUF] TLC T1,-1 ; lh of byte pointer all ones? TLCN T1,-1 ; .. HRLI T1,(POINT 7,) ; yes, make real byte pointer MOVEI T4,<24*5>-1 ; maximum characters allowed in string QUOTE1: MOVEI T3,"V"-100 ; quote character IDPB T3,T1 ; stuff it ILDB T3,T2 ; next char of source string IDPB T3,T1 ; stuff it JUMPE T3,[MOVNI T2,1 ; if zero, back up over last ctrl-V ADJBP T2,T1 ; .. DPB T3,T1 ; wipe it out with null RET] ; and return SOJGE T4,QUOTE1 ; insure no overflow DIE ;Open Log File Opnlog: MOVX T1,.NULIO ; No logs unless SKIPN LOGP ; LOGP is set non-zero RET ; Oh well Movx T1,Gj%sht ; Try Logical Name First Hrroi T2,[Asciz /MAIL:VMAIL.LOG/] GtJFN Erjmp Opnerr Movx T2,<070000,,0>+Of%app Openf ; Open For Append Erjmp Opnerr Ret Opnerr: Hrroi T1,[Asciz /VMAIL: Can't open log file because: /] Esout Movx T1,.priou Hrloi T2,.fhslf Erstr Erjmp .+1 Erjmp .+1 Jrst Fatal ;Time Stamp Log File Dtstmp: Move T1,LogJFN HRROI T2,[ASCIZ/ /] SETZ T3, SOUT% Jerr Seto T2, ; Current Time Odtim IFJER. Hrroi T1,[Asciz /VMAIL: Odtim Failed: /] Esout Movx T1,.priou Hrloi T2,.fhslf Erstr Erjmp .+2 Erjmp .+1 Tmsg < DTSTMP called from > Movx T1,.priou ; Type Pc Of Caller On Terminal Hrrz T2,(P) Movx T3,^D8 ; In Octal Nout Erjmp .+1 Jrst Fatal ; Go Fire Up The World Again ENDIF. Movei T2," " ; Space Bout Ret ;Write Asciz String Pointed To By T1 To Log File Logmsg: Move T2,T1 ; Copy String Pointer Move T1,LogJFN Setzb T3,T4 Sout Jerr Move T1,T2 Ret ;Write Statistics To Log File Lstats: Stkvar ; Move T1,LogJFN ; Move T2,Elptim ; Elapsed Time For Mail Receipt ; Fltr T2,T2 ; Flost It ; Fdvr T2,[100000.0] ; Compute Seconds ; Movx T3,<1b1+Fl%one+Fl%pnt+3b23+3b29> ; Flout ; Type Seconds ; Erjmp [Haltf] ; Never Happens ; Movem T2,Elptm0 ; Save Time ; Log < seconds, > Log < : > Move T1,LogJFN Move T2,Bytcnt ; Byte Count Movx T3,^D10 ; Base 10 Nout Jerr Log < chars > ; Move T1,LogJFN ; Fltr T2,Bytcnt ; Float Byte Count ; Fdvr T2,Elptm0 ; Compute Bytes Per Second ; Movx T3,<1b1+Fl%one+Fl%pnt+5b23+3b29> ; Flout ; Jerr ; Log < chars/sec/ ;> Ret ;Close Net Connection And Reopen It. Re-Enable For Interrupts ; On Connect Initiate Messages CLZNET: MOVEI T1,^D4000 ; Give pipe four seconds to empty DISMS ; .. MOVE T1,NETJFN ; normal close CLOSF IFJER. CALL DTSTMP ; We should complain about these LOG <%Close error for net link: > MOVE T1,LOGJFN HRLOI T2,.FHSLF ERSTR ERJMP .+1 ERJMP .+1 MOVE T1,NETJFN TXO T1,CZ%ABT ; Try real hard to close it CLOSF ; so we don't eat all job 0 JFNs ERJMP .+1 MOVE T1,NETJFN RLJFN ERJMP .+1 ENDIF. CALL OPNLSN ; open connection again RET ; return ;Open The Net Connection And Listen For Connect Initiates Opnlsn: Movx T1,Gj%sht Hrroi T2,[Asciz /Srv:27/] ; Magic Number For Vax Mail Server GtJFN Jerr Movx T2,Of%rd!Of%wr!<100000,,0> Openf Jerr Movem T1,NetJFN Movx T2,.moacn ; Enable For Psi On Network Transitions Movx T3,0b8+<.mocia>B17+<.mocia>B26 ; Channel Zero Mtopr Jerr Movx T1,.fhslf Movx T2,1b0 ; Activate Channel Zero Aic Ret ;Log Name Of Foreign Host T4nhst: Setzm Hstnam ; Zero This String Setzm 1+Hstnam ; .. Move T1,NetJFN ; Get Net JFN Movx T2,.morhn ; Return Host Name Hrroi T3,Hstnam ; Where To Put It Mtopr IFJER. Hrroi T1,[Asciz /???/] Callret Logmsg ; Log confusion ENDIF. Hrroi T1,Hstnam ; Copy Name To Log File Skipe Dbugsw Psout Hrroi T1,Hstnam ; Copy Name To Log File Call Logmsg ; .. Ret ;Set Up To Time Out If Network Too Slow Timeit: Move T1,[.fhslf,,.timel] Move T2,[Timen] ; Milliseconds To Allow Movei T3,1 ; Channel One Timer Jerr Movx T1,.fhslf ; Activate Timer Channel Movx T2,<1b1> Aic Ret ;Cancel Above Timer Request Cncltm: Move T1,[.fhslf,,.timal] ; Remove All Pending Timer Requests Movei T3,1 ; For This Channel Timer Jerr Ret ;Here On Timeout Timout: ; Call Dtstmp Skipn KEPLIV ; Skip if still alive Die ; [153] No activity, dead Setzm KEPLIV ; Clear keep alive flag Push P,T1 ; Save ACs before calling Timeit Push P,T2 Push P,T3 Call Timeit ; Start new timer Pop P,T3 ; Restore ACs before resuming Pop P,T2 Pop P,T1 Debrk ; Allow things to continue ;Here If Net Link Dies While Outputting To It Dmplnk: Cis ; Zap Things Movx T1,Cz%abt ; Abort The Net JFN Hrr T1,NetJFN ; .. Closf ; .. Erjmp .+1 ; Don'T Care Call Dtstmp Log <----Connection aborted > Movx T1,.fhslf ; Deactivate Connect Initiate Channel Movx T2,<1b0> ; .. Dic ; .. Call Cncltm ; Cancel Pending Timer Requests Move T1,LogJFN ; Close Log File Closf Erjmp .+1 ; Jrst VMAIL0 ; Go Wait For New Mail Jrst VMAIL ; Restart on connection abort ;Here On Fatal Wipeout (Jsys Which Can'T Fail Does, For Instance) Fatal: Movx T1,.fhslf Dir ; Disbale Interrupts Cis ; Clear Interrupts ; Remove out-of-synch message on fatal error ;; Move T1,NetJFN ; Type A Record To Force Net Buffers Out ;; Hrroi T2,[Asciz / ;;?VMAIL Internal Error/] ;; Setzb T3,T4 ; Add Question Mark So Mail Isn'T Requeued ;; Soutr ; .. ;; Erjmp .+1 ;; Movei T1,^D5000 ; Wait Five Seconds ;; Disms skipe t1,logJFN Closf Erjmp .+1 setzm logJFN Movx T1,.fhslf!cz%abt ; Abort All JFNs Clzff ; .. ERJMP .+1 ; Ignore errors in the fatal error routine Call Opnlog ; Reopen Log File Movem T1,LogJFN Call Dtstmp Log Tmsg Move T1,LogJFN CLOSF% ERJMP .+1 Movei T1,^D5000 ; Wait Some More Disms Jrst VMAIL ; And Fire Up The World Again ;Disable Capabilities So Quota-Checking Happens Capoff: Push P,T1 ; Don'T Clobber Movx T1,.fhslf ; Get My Caps Rpcap Movem T3,Capenb ; Remember For Later Setz T3, ; No Caps At All Epcap Pop P,T1 ; Restore Ret ;Re-Enable Caps Capon: Push P,T1 ; No Clobberage Movx T1,.fhslf Move T3,Capenb ; Caps We Had Before Epcap Pop P,T1 Ret CRLF0: ASCIZ / / ; FROM DMASER.MAC A==1 B==2 C==3 WAKEUP: SKIPE T2,MYPID ; have a PID already? TDZA T1,T1 ; yes, use it MOVX T1,IP%CPD ; no, create a PID MOVEM T1,IPCBLK+.IPCFL MOVEM T2,IPCBLK+.IPCFS ; PID to use if one there SETZM IPCBLK+.IPCFR ; send to INFO MOVX T1,<.IPCI2+3,,BUFFER> ; length of INFO msg,,where INFO msg is MOVEM T1,IPCBLK+.IPCFP MOVX T1,.IPCIW ; return PID associated with name MOVEM T1,BUFFER+.IPCI0 SETZM BUFFER+.IPCI1 ; duplicate copy not needed DMOVE T1,[ASCII/[SYSTEM]MM/] ; 1st part of PID to look up DMOVEM T1,BUFFER+.IPCI2 MOVE T1,[ASCII/AILR/] ; 2nd part of PID to look up MOVEM T1,BUFFER+.IPCI2+2 MOVX T1,.IPCFP+1 ; length of block MOVEI T2,IPCBLK ; get MMailr's PID MSEND% ERJMP R ; looks like INFO isn't there MOVE T1,IPCBLK+.IPCFS ; get the PID I made MOVEM T1,MYPID ; remember it for next time DO. SETZM IPCBLK+.IPCFL ; no flags SETZM IPCBLK+.IPCFS ; any sender MOVE T1,MYPID ; I'm the receiver MOVEM T1,IPCBLK+.IPCFR MOVX T1,<10,,BUFFER> ; place to put the reply MOVEM T1,IPCBLK+.IPCFP MOVX T1,.IPCFP+1 ; length of block MOVEI T2,IPCBLK ; get reply from INFO MRECV% ERJMP R ; failure irrelevant here LOAD T1,IP%CFC,IPCBLK+.IPCFL ; see who sent message CAIE T1,.IPCCC ; from IPCF? CAIN T1,.IPCCF ; no, from INFO? IFSKP. LOOP. ; no, get another message ENDIF. ENDDO. JN ,IPCBLK+.IPCFL,R ; give up if undeliverable SETZM IPCBLK+.IPCFL ; no flags MOVE T1,MYPID ; I'm the sender MOVEM T1,IPCBLK+.IPCFS MOVE T1,BUFFER+.IPCI1 ; MMailr is the recipient MOVEM T1,IPCBLK+.IPCFR MOVX T1,<1,,BUFFER> ; one word from BUFFER MOVEM T1,IPCBLK+.IPCFP MOVX T1,'PICKUP' ; magic word to wake up MMailr MOVEM T1,BUFFER MOVX C,^D20 DO. MOVX T1,.IPCFP+1 ; length MOVEI T2,IPCBLK ; send wakeup to MMailr MSEND% IFJER. MOVEI T1,^D1000 ; failed, wait a bit DISMS% SOJG C,TOP. ; try a few times RET ; failed, give up ENDIF. ENDDO. MOVX T1,.MUQRY ; query function for MUTIL% MOVEM T1,BUFFER MOVE T1,MYPID ; query packets for our PID MOVEM T1,BUFFER+1 MOVX C,^D20 ; number of retries DO. MOVX T1,.IPCFP+2 ; number of words to return MOVEI T2,BUFFER ; argument block in BUFFER MUTIL% IFJER. MOVEI T1,^D1000 ; wait a bit DISMS% SOJG C,TOP. ; retry a few times RET ENDIF. ENDDO. DO. SETZM IPCBLK+.IPCFL ; no flags SETZM IPCBLK+.IPCFS ; sender is filled in by monitor MOVE T1,MYPID ; I'm the receiver MOVEM T1,IPCBLK+.IPCFR MOVX T1,<10,,BUFFER> ; where MMailr reply will go MOVEM T1,IPCBLK+.IPCFP MOVX T1,.IPCFP+1 ; size of block MOVEI T2,IPCBLK ; get reply from MMailr MRECV% ERJMP .+1 ; error uninteresting here LOAD T1,IP%CFC,IPCBLK+.IPCFP ; get sender code IFN. T1 ; special sender? CAIE T2,.IPCCF ; from INFO CAIN T2,.IPCCP ; or private INFO? LOOP. ; yes, try for another message ENDIF. ENDDO. RET End VMAIL