Trailing-Edge
-
PDP-10 Archives
-
BB-JF18A-BM
-
sources/ms/msfil.mac
There are 7 other files named msfil.mac in the archive. Click here to see a list.
;This software is furnished under a license and may only be used
; or copied in accordance with the terms of such license.
;
;Copyright (C) 1979,1980,1981,1982 by Digital Equipment Corporation
; 1983,1984,1985,1986 Maynard, Massachusetts, USA
TITLE MSFIL - File related support routines for MS
SEARCH GLXMAC,MSUNV,MACSYM
TOPS20< SEARCH MONSYM>
PROLOG (MSFIL)
CPYRYT
MSINIT
.DIRECTIVE FLBLST
SALL
IFNDEF MHACK,<MHACK==0> ; BLISS hack switch
;Define globals
GLOBS ; Storage
GLOBRS ; Routines
;Internal routines
INTERNAL CHECK0,CLOSEF,EXPUNG,GET1,GETFIL,GETHLP,GETJF2,GETLPT
INTERNAL GETNEW,GETOUT,GETPRS,LPTMSG,MOVMSG,PARSEF,PUTMSG
INTERNAL REMAP,SETREF,SETSFL,SHRAGN,UPDBIT,XCLENQ
TOPS20< INTERNAL CLSJF2,SIZFIL,UNMAPF>
TOPS10< INTERNAL FILERR>
;External routines in MS.MAC
TOPS20< EXTERNAL CHECKM,CHNSIZ>
EXTERNAL ALCFOB,CHECKT,CHKDEL,CLRCTO
EXTERNAL CLRFIB,CMDRES,CRIF,CRLF,CTCLOK,CTCOK,DELMSG
EXTERNAL FNDCC,FNDDAT,FNDFRM,FNDMID,FNDREF,FNDRRR,FNDSDT
EXTERNAL FNDSND,FNDSUB,FNDTO,FSCOPY,FSPEC0,MOVST0,MOVSTR
EXTERNAL RECEN0,SSEARC,SUMMRY
EXTERNAL UNSEEN, NFLAGD, NDELET
TOPS10< EXTERNAL CHECKS,ECHOON,FILCRV,FILOPB,LKB,MSGA1,MSGSTR,MSIOWD
EXTERNAL MYPPN,PBLOCK,RDELAY,MSGFD,ATTBLK,LOKAPP>
;External storage in MS.MAC
EXTERNAL CJFNBK,CRFPRT,CRFDIR,ENQBLK,FILPGM,FILPGS,FILSIZ,FILWRT,FLAGS2
EXTERNAL HLPTXT,IDXNUM,IDXSAV,LASTRD,MBOT,MSGFAD,MSGIFJ,MSGJF2
TOPS20< EXTERNAL GTJFN2,JF2BUF,IDXFIL,MYSTR>
EXTERNAL MSGPAG,MSGSSQ,MTOP,OUTFOB,RELFOB,WBOT,WTOP,WWIDH,GTFLAG
SUBTTL GETHLP - read help file
GETHLP: STKVAR <<HLPFOB,2>,HLPIFN>
MOVEI A,FDXSIZ ; Allocate an FD
$CALL M%GMEM ; ..
JUMPF GTHLPE ; No room
HRLZM A,.FDLEN(B) ; Stuff length
TOPS20<
HRLI A,[ASCIZ /HLP:MS.HLP/]
HRRI A,.FDSTG(B) ; Point to filespec area
BLT A,FDXSIZ-1(B)
>
TOPS10<
MOVE A,[SIXBIT /HLP/] ; Init filespec
MOVEM A,.FDSTR(B)
MOVE A,[SIXBIT /MS/]
MOVEM A,.FDNAM(B)
MOVE A,[SIXBIT /HLP/]
MOVEM A,.FDEXT(B)
>;End TOPS10
MOVE A,B ; Set up for ALCFOB
CALL ALCFOB ; Allocate and link FOB
JRST GTHLPE ; No room
MOVX C,FB.LSN ; Don't try to strip LSN's here
ANDCAM C,FOB.CW(B) ; ..
DMOVEM A,HLPFOB ; Save FOB addr and size
$CALL F%IOPN ; Open help file for input
JUMPF [ MOVE A,1+HLPFOB ; Point to FOB
MOVE A,FOB.FD(A) ; Point to FD for error message
$TEXT (KBFTOR,<%Can't read help file ^F/(A)/ because: ^E/[-1]/>)
JRST GTHLP9]
MOVEM A,HLPIFN ; Save IFN
MOVX B,FI.SIZ ; Get length of file in bytes
$CALL F%INFO
ADDI A,<1000*5>-1 ; Round up
IDIVI A,<1000*5> ; Compute pages needed
$CALL M%AQNP ; Snarf them
JUMPF [ WARN (Can't read help file -- insufficient memory)
RET]
LSH A,^D9 ; Compute address of block of pages
HRLI A,(POINT 7,) ; Form byte pointer
MOVEM A,HLPTXT ; Save
MOVE D,A ; Better AC
; JRST GETHP0
GETHP0: MOVE A,HLPIFN
$CALL F%IBUF ; Get next chunk
JUMPF [ CAIE A,EREOF$ ; EOF?
JRST [CMERR (Can't read help file)]
SETZ A, ; Insure ASCIZ
IDPB A,D ; ..
MOVE A,HLPIFN ; Get IFN back
$CALL F%REL ; Close file
JRST GTHLP9]
TOPS10< ; *** Dumb GLXLIB bug patch
TLNN B,770000 ; Bogus byte pointer returned?
TLO B,010000 ; Yes, fix it up then
>;End TOPS10
MOVE C,A ; Byte count
MOVE A,B ; Pointer to buffer just read
MOVE O,D ; Destination
CALL FSCOPY ; Move those bytes
MOVE D,O ; Retain updated destination pointer
JRST GETHP0 ; Do for all hunks
;Here if no room for chunks
GTHLPE: WARN (Can't read help file -- insufficient memory)
;Here to release chunks
GTHLP9: DMOVE A,HLPFOB
CALLRET RELFOB
SUBTTL GET command support code
;Here from GET command, with B pointing to JFN or FD for TOPS10
; to open a message file
GET1:: STKVAR <NEWJFN,<OLDPGS,5>>
MOVEM B,NEWJFN ; Save the jfn away
MOVEI A,OLDPGS ; Save old FDB info
HRLI A,FILPGS
BLT A,4+OLDPGS
MOVE A,NEWJFN ; Do this before OPENF so LASTRD is correct
TOPS20<
CALL SIZFIL ; Get the size of the file, etc.
JRST GETER1 ; Something is not-quite-right
MOVE A,NEWJFN ; Get JFN back
MOVX B,OF%RD!OF%FDT ; Force read date/time update
OPENF
JRST GETERR ; Woops, he goofed
PUSH P,LASTRD ; Save read date-time
CALL SIZFIL ; Re-check file length, now that it's open
JRST [ WARN <Can't determine size of message file>
MOVE A,NEWJFN ;
CALL CJFNS ; Close the new file
POP P,LASTRD ; Restore read date
JRST GETER2]
POP P,LASTRD ; Restore read date
SKIPN FILSIZ ; Is the new file empty?
JRST [ MOVE A,NEWJFN ; Yes, indicate so
SKIPN GTFLAG ; Message been typed already ?
CIETYP ( There are no messages in %1J.) ; No, type warning then
SETOM GTFLAG ; Say message has been typed
MOVE A,NEWJFN ;
CALL CJFNS ; Close the new file, release JFNs
JRST GETER2] ; Restore old file size info
MOVE B,NEWJFN ;
;Note, if F%MOD is turned on, this file is opened as READ only
CALL GTSJFN ; Open the new file as READ/WRITE
JRST [ MOVE A,NEWJFN
CALL CJFNS ; Could not open as READ/WRITE
JRST GETER2] ; Restore old file size info
>;End TOPS20
TOPS10<
MOVE A,NEWJFN ; Get FD pointer back
CALL INILKB ; Init LOOKUP/ENTER block
CALL FILOPR ; Open for read
JRST [ CALL FILERR ; Type appropriate error message
CALL CLRCTO ; Clear ctrl-O
$TEXT (KBFTOR,<%Can't open message file ^F/@NEWJFN/>)
MOVEI A,^D10 ; Insure user gets ten seconds
CALL RDELAY ; to read this message
JRST GETER1] ; Clean up and quit
SETOM LOKAPP ; We don't have an append interlock now.
EXCH A,NEWJFN ; Remember IFN, get FD address back
HLRZ B,.FDLEN(A) ; Get length of FD
HRLZ A,A ; Form BLT ptr to copy to safe place
HRRI A,MSGFD ; Here's where it'll go
ADDI B,MSGFD-1 ; Last address to move
BLT A,(B) ; Move it
CALL SIZLKB ; Get FILSIZ, etc. from LOOKUP block
JFCL ; Account for always skip return
>;End TOPS10
; ..
; ..
;.GET continued...
TOPS20< CALL UNMAPF > ; Flush current message file
PUSH P,F ; Preserve F%MOD
CALL CLOSEF ; close old JFN
POP P,F ; ..
TOPS20< MOVE A,GTJFN2 ; Get the new READ/WRITE JFN
MOVEM A,MSGJF2 ; Place in the usual place
SETZM GTJFN2 > ; No longer in use
MOVE A,NEWJFN ; and setup new JFN
MOVEM A,MSGJFN
CALL GETFLL ; Go parse and do magic
TOPS10< SKIPG MSGJFN ; Did we win a file?
JRST GETER1 > ; No, release stray JFN and quit
SETZM LCNT ; Clear the count of msgs in last sequence
SETOM MSGSSQ ; And the last list too, just in case
TXO F,F%F1 ; Maybe want headers (for MOD)
TXNN F,F%AMOD ; No headers of auto MOD
TXNN F,F%MOD ; If MOD hack - print headers
TXZ F,F%F1 ; No headers, but get new
; TXZE F,F%F2 ; Skip headers (expunge just done)?
; JRST GET2 ; Yes, don't type stuff
TXNN F,F%AMOD ; No summary if auto MOD
CALL SUMMRY ; And a summary of the files contents
GET2:
TOPS10< CALL ECHOON > ; In case monitor command
RET
GETERR: JRETER (Can't open message file)
GETER1:
TOPS20<
MOVE A,NEWJFN ; Flush new jfn (old file still intact)
RLJFN
JFCL
>;End TOPS20
TOPS10<
MOVEI A,MSGFD ; Re-init LOOKUP/ENTER block
CALL INILKB ; ..
>;End TOPS10
GETER2: MOVEI A,FILPGS ; Restore file size poop
HRLI A,OLDPGS
BLT A,FILPGS+4
TXZ F,F%MOD ; Turn off MOD
JRST GET2 ; Clean up and quit
SUBTTL EXPUNGE support code
SYSWRN: ; for neatness in code on this page
TOPS10< WARN (Use the command GET STD:MAIL.TXT to expunge messages)>
TOPS20< WARN (Use the command GET POBOX:<SYSTEM>MAIL.TXT to expunge messages)>
RET
EXPUNG::SKIPN NDELET ; If there aren't any deleted messages
RET ; We can leave work early
TXNE F,F%MOD ; MOD hack? (System mail?)
JRST SYSWRN ; Issue warning msg and quit
; Initialization for Expunge
TRVAR <MMSGPG,MMSGDX,MWRTOP,MWRBOT,PR1,PR2,PR3,NPCNT,WRADR,WRTOP,WRBOT,WRPAG,WRPGN,WVOL>
EXPN03: SETZB L,M ; Zero offset, start with first msg
CALL CTCLOK ; Yes, prevent ^C from stopping this scramblage
JRST [ WARN <Cannot expunge deleted messages - another reader exists>
RET] ; Quit now
TOPS10< MOVE A,MSGJFN ; Prevent incoming mail while this goes on
CALL APPNQ0 ; ..
JRST [ WARN (Cannot expunge deleted messages - mail is arriving)
CALL CTCOK
RET]
CALL CHECK0 ; See if any new mail
JRST EXPN02 ; None exists, no problem
CALL CTCOK ; Oops, some arrived -- release expunge lock
CALL APPDEQ ; Release append interlock
CALL CLOSEF ; Better go reparse it all
MOVEI B,MSGFD ; Read file again
TXO F,F%AMOD ; (Crock - sigh) don't type summary
CALL GET1 ; To prevent loss of new messages
TXZ F,F%AMOD
JRST EXPN03 ; OK, try it again
>;End TOPS10
EXPN02: MOVE A,NDELET ; Number of deleted messages
SOS A ; Number of deleted messages with zero offset
CAMN A,LASTM ; Have we deleted all the messages?
JRST EXPDEL ; Yes, then go delete the file
CALL GETJF2 ; Get write JFN so no one interferes
JRST [ WARN <Can't open file for write, so cannot expunge>
CALL CTCOK ; Unlock file
TOPS10< CALL APPDEQ >
RET]
; Get pages for writing
$CALL M%FPGS ; How many pages do we have free?
MOVE B,A
SUBI B,MSGIDN
JUMPLE B,[ WARN (Can't get pages for expunging)
TOPS20< CALL CLWJFN > ; Close the READ/WRITE JFN
; (CLSFL2,RELJF2,CTCOK,APPDEQ AND MAYBE MORE)
RET]
CAMLE B,WWIDH ; If too much
MOVE B,WWIDH ; Be modest
MOVE A,B ; Take them
MOVEM B,WRPGN ;
IMULI B,5000 ; Write window volume
MOVEM B,WVOL
TOPS10< SETZM WRBOT ; Init the write window bottom
SOS B ; and
MOVEM B,WRTOP ; top
>
$CALL M%AQNP
MOVEM A,WRPAG ; Page number
ASH A,^D9 ; Address
MOVEM A,WRADR
TOPS10< CALL CHECKT> ; In case new mail
TOPS20< CALL CHECKM> ; In case new mail
SETZB X,MMSGDX ; Init count of bytes saved
CITYPE < Expunging deleted messages > ; Type message
$CALL K%FLSH ; This can take a while
SETZB O,V ; Init pointer to output area
;Main expunge loop starts here
EXPN00: MOVX A,M%DELE ; Deleted bit
GTMBL (M,B) ; Get ptr to message block
TDNN A,MSGBTS(B) ; Is it deleted?
JRST EXPN20 ; No, must save it
EXPN10:
TOPS20< JUMPN L,EXPN15
MOVE V,X
MOVE O,V
PUSH P,B
CALL WRMAP
POP P,B
EXPN15: >
MOVE A,MSGALN(B) ; Get length of deleted msg
SUB L,A ; Increment count of byte offset
JRST EXPN30 ; And go process next msg
;Message is NOT deleted, save it
EXPN20: MOVE C,MSGALN(B) ; Length of message
ADD X,C ; Keep track of total
TOPS20< JUMPE L,EXPN30 > ; If no bytes deleted yet, no moving
MOVE V,MSGALL(B) ; Get starting byte of message
MOVNM C,PR3 ;STORE CHAR COUNT
MOVEM V,PR1 ;SAVE CHAR POINTERS
MOVEM O,PR2
TRNA
EXP19: MOVN C,C ; Make C positive
EXP21: CALL GTBFL ;MAKE IT NOT SLEEPING
CAML O,WRBOT
CAMLE O,WRTOP
CALL WRMAP
MOVE B,WTOP
SUB B,V ;ARE WE ALL RIGHT IN TERMS OF READING ?
AOS B
CAMGE B,C
MOVE C,B ;NO, TAKE AS MUCH AS POSSIBLE NOW
MOVE B,WRTOP
SUB B,O ;HOW ABOUT WRITING ?
AOS B
CAMGE B,C ;DO SAME TRICK
MOVE C,B
SUB O,WRBOT
EXCH V,O
MOVE A,WRADR
IMULI A,5
ADD V,A
CHR2BP ; Get byte pointer to WRITE AREA
EXCH A,O ;POINTER TO O, V TO A
MOVE V,A
SUB V,WBOT
MOVE A,MSGFAD
IMULI A,5
ADD V,A
CHR2BP ; Get byte pointer to READ AREA
ADDM C,PR3 ;CORRECT BYTE NUMBER LEFT
ADDM C,PR2 ;AND CHAR POINTER
ADDM C,PR1
CALL FSCOPY ; Do a fast string copy
MOVE V,PR1 ;RESTORE CHAR POINTERS
MOVE O,PR2
SKIPE C,PR3 ; All done?
JRST EXP19 ; No
; JRST EXP22 ; Yes, proceed
EXP22: GTMBL (M,B) ; Get ptr to message block
ADDM L,MSGALL(B) ; Update positions
ADDM L,MSGBOD(B)
SKIPE MSGSND(B) ; Sender:
ADDM L,MSGSND(B) ;
SKIPE MSGSUB(B) ; Subject
ADDM L,MSGSUB(B)
SKIPE MSGFRM(B) ; From:
ADDM L,MSGFRM(B)
SKIPE MSGTO(B) ; To:
ADDM L,MSGTO(B)
SKIPE MSGCC(B) ; Cc:
ADDM L,MSGCC(B)
SKIPE MSGMID(B) ; Message Id:
ADDM L,MSGMID(B)
SKIPE MSGREF(B) ; References:
ADDM L,MSGREF(B)
EXPN30: CAMGE M,LASTM ; At the last msg?
AOJA M,EXPN00 ; No, do next then
TOPS10< MOVE A,X ; Get the number of bytes saved
CALL SIZEXP ; And update all the appropriate information
JFCL > ; Simply cannot happen
TOPS20< MOVE B,X ; See how many pages touched
IDIVI B,BY2PAG
SKIPE C
AOS B
MOVEM B,NPCNT ; Save new count for later
>
SETZB B,D ; Make a null in case needed
MOVE V,X ; Form byte ptr to last byte unfilled
SUB V,WRBOT
MOVE C,WRADR ; First word in message file
IMULI C,5 ; First byte
ADD V,C ; Plus bytes OK gives last unfilled
CHR2BP ; ..
EXPN31: TLNN A,760000 ; Have we zapped to a word boundary?
JRST EXPN35 ; Yes, we're OK then
IDPB B,A ; No, zero rest of this word
AOJA D,EXPN31 ; Count nulls added and pad to word boundary
EXPN35:
TOPS20<
CALL UNMAPF ; Release the read window, and
CALL UNMAP ; release the write window to prevent PMAP error
HRRZ C,FILPGS ; Number we had mapped to start
SUB C,NPCNT ; Less number touched
JUMPE C,EXPN36 ; All pages touched
SETO A,
HRLI C,(PM%CNT)
HRLZ B,MSGJF2 ; in the file
HRR B,NPCNT ; Start here
PMAP ; ...
ERJMP EXPNER ; Pages mapped elsewhere
>;End TOPS20
TOPS10<
MOVE B,X ; Get bytes to write
SUB B,WRBOT ; And subtracting what has gone before
ADDI B,4 ; Force roundup
IDIVI B,5 ; Compute words
CALL EXPOUT ; Write these bytes out
>;End TOPS10
; ..
; ..
EXPN36:
TOPS20<
MOVE B,NPCNT ; Get back count of pages touched
HRRM B,FILPGS ; Set up new count of pages
MOVE A,MSGJF2
HRLI A,.FBSIZ
SETO B,
MOVE C,X ; Update byte count
CHFDB
ERJMP [JWARN (Can't set byte count for message file)
JRST .+1]
LDB B,[POINT 6,FILPGS,11] ; Get byte size
CAIN B,7 ; If not 7,
JRST EXPN32
HRLI A,.FBBYV ; Make it be
MOVSI B,(FB%BSZ)
MOVSI C,(7B11)
CHFDB
ERJMP [JWARN (Can't set byte size for message file)
JRST EXPN32]
; JRST EXPN32
>;End TOPS20
; Here to update Message Index
EXPN32: SETZB X,M ; Update message numbers
SKIPGE MSGIFJ ; More than 512 messages?
IFNSK. ; No skip if < 512
SETZM MWRBOT ; Zero bottom boundary
MOVEI A,777 ; Set upper boundary
MOVEM A,MWRTOP ; To 777 (511.) messages
MOVEI A,MSGIDX ; Set up size of a window
MOVEM A,MMSGDX ; And save it here
ELSE. ; Otherwise, if > 512 messages
TOPS10< halt >
tops20< MOVEI A,MSGIDN ; Ask for this many pages
$CALL M%AQNP ; Ask GLXLIB
JUMPF [ WARN <Expunge failed due to insufficient memory.>
MOVE A,WRPGN ; Release the previously acquired memory
MOVE B,WRPAG ;
$CALL M%RLNP ;
CALL CLSJF2 ; Close EXPUNGE JFN
JRST RELJF2 ] ; Punt
MOVEM A,MMSGPG ; Save Page number of buffer
ASH A,^D9 ; Make it into an address
MOVEM A,MMSGDX > ; And save that too.
ENDIF. ; All done
EXPN41: GTMBL (M,B) ; Get ptr to message block
;Here we have old message number M, about to be deleted or become message
; number X. Fix the SAME array accordingly.
MOVE C,[POINT 18,MSGSSQ]
SKIPA D,C
DRPSAM: IDPB A,D
FIXSAM: ILDB A,C
CAIN A,-1
JRST ALLFXD
CAIE A,(M) ;REFERENCE TO CURRENT MESSAGE?
JRST DRPSAM ;NO, LEAVE IT ALONE FOR NOW
MOVX A,M%DELE ;YES, SEE IF DELETED
TDNN A,MSGBTS(B) ;IF DELETED, NEGLECT TO WRITE IT BACK
IDPB X,D ;(POSSIBLY) CHANGED, WRITE NEW VALUE IN
JRST FIXSAM
ALLFXD: IDPB A,D
MOVX A,M%DELE
TDNE A,MSGBTS(B) ; Deleted?
JRST EXPN42 ; Yes, skip it then
CAMN X,M ; No, still none deleted?
AOJA X,EXPN42 ; Yes, keep looking
SKIPE MMSGDX ; Is there an index window?
JRST EXMOVE ; No, don't map it
tops10< halt >
tops20<
EXPP1: MOVE A,X
TRZ A,777
MOVEM A,MWRBOT
MOVE B,A
ADDI B,777
MOVEM B,MWRTOP
ASH A,^D-9
IMULI A,MSGIDN ;FILE PAGE NUMBER
HRL A,MSGIFJ
MOVE B,MMSGPG
HRLI B,.FHSLF ;PROCESS DATA
MOVEI C,MSGIDN
HRLI C,(PM%CNT!PM%WR) ;GET THE PAGES
PMAP
>
EXMOVE: MOVE A,X ;WRITE MESSAGE NUMBER
CAML A,MWRBOT
CAMLE A,MWRTOP
tops20< JRST EXRMP > ;REMAP IF NOT GOOD
tops10< halt >
SUB A,MWRBOT
IMULI A,MSGIDN
ADD A,MMSGDX ; Write address in A
GTMBL (M,B) ; get index for read
HRL A,B
HRRZ B,A
ADDI B,MSGIDN-2
BLT A,(B) ;MOVE IT
AOJA X,EXPN42 ; No, move this msg's data down n places, where
TOPS20<
EXRMP: SETOM A ;UNMAP OLD PAGES
MOVE B,MMSGPG
HRLI B,.FHSLF
MOVEI C,MSGIDN
HRLI C,(PM%CNT)
PMAP ;UNMAP
JRST EXPP1 ;GET NEW PAGES
>
EXPN42: CAMGE M,LASTM ; Done?
AOJA M,EXPN41 ; No, step to next message
SOJ X,
MOVEM X,LASTM ; Yes, update new count
MOVE M,X ; And current message #
TOPS20< PUSH P,LASTRD ; Don't hack last read date
CALL UNMAP ;UNMAP PAGES
HRRZ A,MSGJF2 ; Write JFN
CALL SIZFIL ; Update knowledge of file size
WARN <Internal error - SIZFIL failed at EXPN42>
POP P,LASTRD
>
$TEXT (KBFTOR,<- OK>) ; Type reassurance
CALL CLSJF2 ; And go close it up
MOVE A,WRPGN
MOVE B,WRPAG ;RELEASE THE MEMORY
$CALL M%RLNP
tops20<
SKIPGE MSGIFJ ;DO WE HAVE INDEX FILE ?
JRST EXPNGT ; And REG-GET the file
SETOM A
MOVE B,MMSGPG
HRLI B,.FHSLF ;YES, UNMAP PAGES
MOVEI C,MSGIDN
HRLI C,(PM%CNT)
PMAP
; JRST EXPNGT ;NOW REPARSE FILE FROM THE 'M' MESSAGE
EXPNGT: HRROI A,STRBUF
MOVE B,MSGJFN ; One we do have
SETZ C,
JFNS
MOVSI A,(GJ%OLD!GJ%SHT)
HRROI B,STRBUF
GTJFN
ERJMP [JRETER (Cannot get second JFN on file)
RET]
TXO F,F%AMOD
MOVE B,A ; Put JFN in the right AC for GET1
CALL GET1
TXZ F,F%AMOD
RET
>;End TOPS20
TOPS10< CALL APPDEQ ; Release append interlock
CALL CLOSEF ; Close first opening as well
TXO F,F%F2 ; Don't type status of file
MOVEI B,MSGFD ; Point to FD we used to open this file
CALL GET1 ; Get and parse file again, and return
TXZ F,F%F2 ; Remember to turn this off
RET ; Home, James
; Ideally we would call parsef.....
; CALLRET PARSEF ; Reparse the file from 1st message that moved
EXPOUT: MOVNS B ; Negate for IOWD
HRLZS B ; Position for same
HRR B,WRADR ; Address of buffer
SUBI B,1 ; minus one
MOVEM B,MSIOWD ; Store IOWD
SETZM MSIOWD+1 ; Tie off list
MOVE B,[OUT MSIOWD] ; Instruction to write file
MOVE A,MSGJF2 ; Get channel for write
LSH A,^D23 ; Into right position
IOR B,A ; Form complete instruction
XCT B
RET ; OK
FATAL (Can't update message file during expunge)
>;End TOPS10
;Here when all messages deleted
EXPDEL: CITYPE < All messages deleted, deleting file.
>
CALL DEQFIL ; DEQ the lock on message file
TOPS20<
CALL UNMAPF
MOVE A,MSGJFN ; Close the message file
TXO A,CO%NRJ ; But keep the JFN around
CLOSF ; Close it
JWARN (Cannot close message file)
MOVE A,MSGJFN ; Get the JFN back
DELF ; Now delete the message file
JWARN (Cannot delete message file)
CALL CTCOK
SKIPG MSGIFJ ;DO WE HAVE BLOCK FILE ?
JRST EXPNN ;NO
MOVEI B,MSGIDX
ASH B,^D-9
HRLI B,.FHSLF
MOVEI C,MSGIDN
HRLI C,(PM%CNT)
SETOM A
PMAP ;UNMAP PAGES
HRR B,MMSGPG ;IN BOTH PLACES
PMAP
MOVEI A,MSGIDN
$CALL M%RLNP ;RRELEASE THE MEMORY
MOVX A,CO%NRJ
HRRZ A,MSGIFJ
CLOSF ; Close it
JWARN (Cannot close index file)
MOVX A,DF%EXP ;EXPUNGE IT
DELF
JRST .+1
SETZM MBOT
MOVEI A,777
MOVEM A,MTOP
>;End TOPS20
TOPS10<
CALL CLSJF2 ; Close second opening, if any
CALL APPDEQ ; Release append interlock
HRL A,MSGJFN ; Get channel again for FILOP.
TLO A,(FO.UOC) ;Use Open Channel for delete
HRRI A,.FODLT ; Delete function
MOVEM A,FILOPB+.FOFNC ; Stuff into FILOP. block
SETZM FILOPB+.FOLEB ;Don't need filspec because of FO.UOC
MOVE A,[.FOPPN+1,,FILOPB]
FILOP. A,
WARN (Cannot delete message file)
>;End TOPS10
EXPNN: SETOM MSGJFN ; Mark that we have no JFNs
TOPS20< SETZM MSGJF2>
TOPS10< SETOM MSGJF2>
SETOM MSGIFJ
SETZM WBOT
SETZM WTOP
RET
TOPS20<
; Here if expunge lost
EXPNER: $STOP (BFD, Bad Filepage Delete)
CALL UNMAPF
CALL UNMAP ; Unmap all pages
CALL CLSJF2 ; Close file
CALL RELJF2 ; and release JFN
CALL GETFIL ; Re-read and parse mail file
RET ; Return
>;End TOPS20
TOPS10<
APPNQ0: AOSE LOKAPP ; Do I already have the interlock?
RETSKP ; Yes, don't get it again
TXO A,EQ.FBL ; Suppress level numbers
MOVEM A,APPBLK+.ENQFL+.ENQRI+1
MOVE A,[.ENQAA,,APPBLK]
ENQ. A,
JRST [SOS LOKAPP ;DIDN'T GET IT, FIX COUNT
RET] ; Probably another writer
RETSKP ; Win!!
;Release the append lock
APPDEQ: SOSL LOKAPP ; Count depth of lock
RET ; Someone higher than me still has it
SETOM LOKAPP ; Just in case...
MOVE A,[.DEQID,,APPQID]
DEQ. A,
WARN (Can't release message file append interlock)
RET
>;End TOPS10
; ROUTINE MAPS PROCESS TO THE WRITE FILE ACCORDING TO O
WRMAP:
TOPS10< MOVE B,O ; Save new bottom of
MOVEM B,WRBOT ; the write window
ADD B,WVOL ; And compute new
SOS B ; top of the
MOVEM B,WRTOP ; write window
MOVE B,WVOL ; Bytes written
IDIVI B,5 ; Make that words
CALLRET EXPOUT ; Output them and return
>;End TOPS10
TOPS20< PUSH P,C ;IMPORTANT
SKIPE L ;IF NOT FIRST ENTRY
CALL UNMAP ;UNMAP STUFF
MOVE B,O ;BYTE NUMBER
IDIVI B,5000 ;FILE PAGE NUMBER
MOVE A,B ;SAVE IT
IMULI B,5000 ;WRITE WINDOW BOTTOM CHAR POINTER
MOVEM B,WRBOT ;SAVE IT
ADD B,WVOL ;TO CONTROL WRITING
SOS B
MOVEM B,WRTOP ;STORE IT
MOVE C,WRPGN
HRL A,MSGJF2 ;AND JFN
MOVE B,WRPAG ;PROCESS PAGE
HRLI B,.FHSLF
HRLI C,(PM%CNT!PM%WR!PM%PLD)
PMAP ;MAP IT OUT
POP P,C
RET
UNMAP: SETOM A
MOVE B,WRPAG
HRLI B,.FHSLF
MOVE C,WRPGN
HRLI C,(PM%CNT)
PMAP
RET
>
SUBTTL Expunge command - ENQ/DEQ Routines
;Get shared ENQ on message file (so potential expungers know not to)
SHRENQ:
TOPS20<
MOVSI A,(EN%SHR+EN%BLN) ; ENQ for shared access, ignore level numbers
HRR A,MSGJFN ; Lock the message file
MOVEM A,ENQBLK+.ENQLV ; ..
MOVEI A,.ENQAA ; Acquire the lock now
MOVEI B,ENQBLK ; Address of arg block
ENQ ; This should always work
ERJMPR SHRENF
RETSKP
SHRENF: CAIN A,OPNX9
RET
JCERR (Cannot lock message file)
>;End TOPS20
TOPS10<
MOVE A,MSGJFN ; Get IFN of message file
MOVX B,NQID ; Use standard ID
MOVEM B,ENQBLK+.ENQRI ; ..
JRST SHRNQ1
SHRNQ0: MOVX B,NQID+1 ; Use alternate ID
MOVEM B,ENQBLK+.ENQRI ; ..
SHRNQ1: IOR A,[EQ.FSR+EQ.FBL] ; ENQ for shared access, ignore level numbers
MOVEM A,ENQBLK+.ENQFL+.ENQRI+1 ; Save in ENQ. block
MOVE A,[.ENQAA,,ENQBLK] ; Acquire the lock now, fail if can't
ENQ. A, ; ..
JRST [ CAIN A,ENQQE% ; Insufficient ENQ/DEQ quota?
WARN (You have no ENQ-DEQ quota -- see your system administrator)
RET]
RETSKP
>;End TOPS10
;Make existing shared lock exclusive, to prevent scramblage
;Returns +1: Another reader exists, can't scramble the bits
; +2: Success, we're only reader and now have file locked
XCLENQ:
TOPS20<
MOVSI A,(EN%BLN) ; Ignore level numbers, non-shared ENQ
HRR A,MSGJFN ; JFN of message file
MOVEM A,ENQBLK+.ENQLV ; Stuff into ENQ block
MOVEI A,.ENQMA ; Modify existing lock (make exclusive)
MOVEI B,ENQBLK ; ..
ENQ ; ..
ERJMP R ; Can't - must be other readers
>;End TOPS20
TOPS10<
CALL DEQFIL ; Cannot upgrade a lock, therefore give it away
MOVE A,MSGJFN ; Get IFN of message file
IOR A,[EQ.FBL] ; Ignore level numbers, exclusive access
MOVEM A,ENQBLK+.ENQFL+.ENQRI+1 ; ..
MOVX A,NQID ; Use standard ENQ ID
MOVEM A,ENQBLK+.ENQRI ; ..
MOVE A,[.ENQAA,,ENQBLK] ; Get exclusive access
ENQ. A, ; ..
JRST [ CALL SHRENQ ; Probably another reader
JFCL ; Restore shared lock
RET] ; and return failure
>;End TOPS10
RETSKP ; Success
;Make existing, possibly exclusive, lock shared again
SHRAGN:
TOPS20<
MOVSI A,(EN%BLN+EN%SHR) ; Make ENQ shared again
HRR A,MSGJFN ; JFN of message file
MOVEM A,ENQBLK+.ENQLV
MOVEI A,.ENQMA ; Modify access
MOVEI B,ENQBLK
ENQ ; ..
ERJMP .+1 ; We might not have obtained exclusive access
>;End TOPS20
TOPS10<
MOVE A,MSGJFN ; Get IFN of message file
IOR A,[EQ.FBL+EQ.FSR] ; Make shared, ignore level numbers
MOVEM A,ENQBLK+.ENQFL+.ENQRI+1 ; ..
MOVX A,NQID ; Use standard ENQ ID
MOVEM A,ENQBLK+.ENQRI ; ..
MOVE A,[.ENQMA,,ENQBLK]
ENQ. A,
JFCL ; Might already be shared
>;End TOPS10
RET
;Release the lock on a message file entirely
DEQFIL:
TOPS20<
MOVEI A,.DEQID ; Unlock file first
MOVEI B,NQID ; ..
DEQ
ERJMPS .+1
RET
>;End TOPS20
TOPS10<
SKIPA A,[.DEQID,,NQID] ; Release this specific lock
DEQFL0: MOVE A,[.DEQID,,NQID+1] ; Alternate ID (for other users' mail files)
DEQ. A, ; ..
WARN (Cannot release lock on message file - error code %1O)
RET
>;End TOPS10
SUBTTL Routines to open output files and write messages to them
;GETOUT - Parse filespec and open for append
;GETNEW - Same, but open for write
;GETPRS - Parse filespec only, don't open
GETPRS: TXO F,F%F2 ; Note parse-only
GETNEW: TXZA F,F%F1 ; Note flavor
GETOUT: TXO F,F%F1 ; ..
TOPS20<
MOVX A,GJ%MSG ; Just message
MOVEM A,CJFNBK+.GJGEN
SETZM CJFNBK+.GJNAM ; No default name
HRROI A,CRFPRT ; Default protection
SKIPE CRFPRT ; if explicitly specified
MOVEM A,CJFNBK+.GJPRO ; ..
>;End TOPS20
TOPS10<
SKIPN CRFDIR ; Default directory given?
JRST GETOU0 ; No
MOVE A,[CRFDIR,,CJFNBK+.FDPPN] ; Yes, fill it in before parse
BLT A,CJFNBK+FDXSIZ-1
>;End TOPS10
GETOU0: MOVEI A,[FLDDB. (.CMCFM,,,,,[FLDDB. (.CMFIL,CM%SDH,,<filespec>)])]
CALL FSPEC0 ; Parse filespec and set up FOB
JRST [TXZ F,F%F2 ; Don't leave bits lying around
RET]
DMOVEM A,OUTFOB ; Remember this FOB
TOPS10<
MOVEI A,ATTBLK ; Set up default protection
SKIPE CRFPRT ; If we have used the SET DEF PROT command
MOVEM A,FOB.AB(B) ; then have GALAXY use it for the open.
>
TXZE F,F%F2 ; Only want to parse filespec?
RETSKP ; Yes, just quit now
MOVE C,[$CALL F%OOPN] ; Decide which open flavor to use
TXNE F,F%F1 ; Want append instead of clobber?
MOVE C,[$CALL F%AOPN] ; Yes, do append call
XCT C ; Open the file
JUMPF [ MOVE A,OUTFOB+1 ; Get FOB address
MOVE A,FOB.FD(A) ; Point to FD for error message
$TEXT (KBFTOR,<?Can't open ^F/(A)/ for write because: ^E/[-1]/>)
SETZM OUTIFN
DMOVE A,OUTFOB ; Deallocate chunks
CALLRET RELFOB] ; and return
MOVEM A,OUTIFN ; Save IFN
RETSKP
;Open LPT for output
;Return +1: failure, message already printed
; +2: success, IFN of printer in OUTIFN
GETLPT: STKVAR <LPTFD>
MOVEI A,FDXSIZ ; Allocate space for largest FD
$CALL M%GMEM ; ..
JUMPF GETLPE ; No room
HRLZM A,.FDLEN(B) ; Stuff length into FD
MOVEM B,LPTFD ; Save address
MOVE A,B
; This code ends up specifying /UNIT:0 by the time GALAXY gets around
; to actually printing the message. There's no reason to limit MS
; listings to only unit 0, so....
REPEAT 0,<
TOPS20<
HRLI A,(POINT 7,) ; Form byte pointer
ADDI A,.FDSTG ; Where filespec goes
MOVEI B,[ASCIZ /LL:MS-Output.LST/]
CALL MOVST0
MOVE A,LPTFD ; Restore FD address
>;End TOPS20
TOPS10<
DMOVE B,[SIXBIT /LL/
SIXBIT /MS-OUT/]
DMOVEM B,.FDSTR(A)
MOVE B,[SIXBIT /LST/]
MOVEM B,.FDEXT(A)
>;End TOPS10
CALL ALCFOB ; Allocate and link FOB
JRST GETLPE ; No room
DMOVEM A,OUTFOB ; Save address
$CALL F%OOPN ; Open for write
JUMPF GETLPX ; Hmmm... go try LPT instead of LL
MOVEM A,OUTIFN ; Save IFN
RETSKP
GETLPX: MOVE A,LPTFD ; Try LPT, LL didn't work
> ; End of REPEAT 0 to remove LL: code
TOPS20<
HRLI A,(POINT 7,)
ADDI A,.FDSTG
MOVEI B,[ASCIZ /LPT:MS-Output.LST/]
CALL MOVST0
MOVE A,LPTFD ; Restore FD address
TXO F,F%F1 ; Make sure we can use user's def of LPT:
>;End TOPS20
TOPS10<
MOVE B,[SIXBIT /LPT/]
MOVEM B,.FDSTR(A)
>;End TOPS10
CALL ALCFOB ; Allocate and link FOB
JRST GETLPE ; No room
DMOVEM A,OUTFOB ; Save address
$CALL F%OOPN ; ..
JUMPF [ DMOVE A,OUTFOB ; Don't lose chunks
CALL RELFOB
JRST GETLPE]
MOVEM A,OUTIFN ; Save IFN
RETSKP
GETLPE: $TEXT (KBFTOR,<?Can't open LPT for output because: ^E/[-1]/>)
RET ; Failure return
MOVMSG: CALL CHKDEL
RET
CALL PUTMS1
SKIPN OUTIFN ; If file still open, PUTMS1 worked OK
RET ; Oops, there was an error, don't delete it
CALLRET DELMSG ; Move deletes message
LPTMSG: CALL PUTMSG ; Put it out there
MOVX A,M%DELE ; Skip for deleted messages
GTMBL (M,B) ; Get ptr to message block
TDNE A,MSGBTS(B) ; ..
RET
SKIPN A,OUTIFN
RET ; Just quit if file went away
MOVEI B,14 ; Form feed
$CALL F%OBYT
RET
;PUTMSG - write message to a file, IFN in OUTIFN
; Constructs new header line from scratch, in case file damage
; has garbaged the one in the message file. At worst, this will
; make a bad assumption about the message date (today, if real
; date can't be found)
PUTMSG: CALL CHKDEL ; Not deleted msgs
RET
PUTMS1: GTMBL (M,B) ; Get ptr to message block
MOVE V,MSGBOD(B) ; Get start of the message body
CALL SETSFL ; Make sure we are all right
HRRZ A,MSGBTS(B) ; Get message bits
$TEXT (PUTMSW,<^H/MSGDAT(B)/,^D/MSGBON(B)/;^O12R0/A/>)
SKIPN C,MSGBON(B) ; Length
RET ; Zero length (file damage) -- don't write
SKIPN OUTIFN ; Did $TEXT encounter error?
JRST PUTERR ; Yes, quit now
PUTMS2: CALL GTBFL
AOS V
MOVE B,A
MOVE A,OUTIFN
$CALL F%OBYT ; Write to the file
JUMPF PUTERR
SOJG C,PUTMS2 ; Count down bytes
MOVE A,OUTIFN
$CALL F%CHKP ; Force buffers out
JUMPF PUTERR ; Oops, report error
; This code ends up creating a second output file for the print/list commands
; so unless it breaks something else...
REPEAT 0,<
MOVE A,OUTIFN ; OK, close the file
$CALL F%REL ; to force correct updating
DMOVE A,OUTFOB ; and reopen it
$CALL F%AOPN ; ..
JUMPF PUTERR
MOVEM A,OUTIFN
> ; End of Repeat 0
RET
PUTMSW: MOVE B,A ; Put byte in right AC for F%OBYT
SKIPE A,OUTIFN ; Where to write this one
$CALL F%OBYT
JUMPF [ SETZM OUTIFN ; Flag error for caller
RET]
RET
;Here on error writing msg
PUTERR: CALL CLRCTO ; Clear ctrl-O
CALL CLRFIB ; Clear typehead
MOVE A,FLAGS2 ; Want sequence messages?
TXNN A,F2%NSQ ; ?
JRST [ MOVE B,MSGSEQ
ADD B,[POINT 18,0,17]
CAME L,B
CALL PRTSQS ; Yes, print close of sequence
JRST .+1]
SETOM LSTMSG ; Re-init message sequence printer state
CALL CRIF ; Get to left margin
$TEXT (KBFTOR,<?Cannot write message because: ^E/[-1]/>)
SKIPE A,OUTIFN ; Abort file
$CALL F%RREL ; ..
SETZM OUTIFN
$TEXT (KBFTOR,<? Skipping messages: ^A>)
PUTER0: MOVE A,FLAGS2
TXNN A,F2%NSQ ; If not suppressing sequence display,
CALL PRTSEQ ; print start of sequence
CALL NXTSEQ ; Skip to end of list
RET ; Return when done, SEQUE0 will do the PRTSQS
JRST PUTER0
;Check to see if new mail has appeared
;Return +1: no new mail
; +2: new mail exists, caller should parse it
CHECK0: SKIPG MSGJFN ; Have a file?
CALLRET CHKNEW ; No - see if new file appeared
PUSH P,FILSIZ ; Save current size
PUSH P,LASTRD ; Don't hack last read date/time
TOPS20< MOVE A,MSGJFN >
TOPS10< MOVEI A,MSGFD >
CALL SIZFIL ; Get the current poop on it
JRST [ WARN (Can't determine existence of new mail)
POP P,LASTRD
POP P,(P) ; Clean PDL
JRST CLOSEF] ; Return error
POP P,LASTRD ; Restore last read date/time
POP P,T ; Get back old size
EXCH T,FILSIZ ; Restore old size, save new in t
MOVE A,FILWRT
CAMN T,FILSIZ ; File size changed?
RET ; No, nothing changed
MOVEM T,FILSIZ ; Yes - store new size info
RETSKP ; and skip return
; Update last time the mail file was read
TOPS10<
SETREF: $CALL I%NOW
MOVE C,A ; Save time
$CALL I%NOW ; Wait for time to elapse
CAMN C,A
JRST .-2
MOVEM A,LASTRD
RET
>
; Set read date-time for JFN in 1
TOPS20<
SETREF: PUSH P,A ; Save jfn
$CALL I%NOW
MOVE C,A ; Save time
$CALL I%NOW ; Wait for time to elapse
CAMN C,A
JRST .-2
MOVE C,A ; Set read date to now
MOVEM C,LASTRD ; Update last time file was read
POP P,A ; JFN to update
HRLI A,.FBREF
SETO B, ; Cause we are going to reparse
CHFDB
ERJMP .+1 ; Maybe no access, dont worry
RET
>;End TOPS20
;Check if MAIL.TXT has appeared
CHKNEW: CALL GETFIL ; Has it?
RET ; Nope - return
SETOM LASTM ; Flag for full parse
SETZ M, ; Current message
RETSKP
; Close the file
CLOSEF: SKIPG MSGJFN ; Any message JFN?
JRST CLOSF1 ; No, skip this
CALL DEQFIL ; Release ENQ lock
MOVE A,MSGJFN
TOPS20< CLOSF ; Close it
JRST [ CAIE A,CLSX1 ; Closed already?
JWARN (Cannot close message file)
JRST .+1] ;
>
TOPS10< CALL CLSFIL > ; Close it
SKIPGE MSGIFJ ;DO WE HAVE BLOCK FILE ?
JRST CLOSF2 ;NO
;NEED STUFF HERE
TOPS20<
MOVEI B,MSGIDX
ASH B,^D-9
HRLI B,.FHSLF
MOVEI C,MSGIDN
HRLI C,(PM%CNT)
SETOM A
PMAP ;UNMAP PAGES
MOVX A,CO%NRJ
HRR A,MSGIFJ
CLOSF ; Close it
JWARN (Cannot close index file)
MOVX A,DF%EXP ;EXPUNGE IT
HRR A,MSGIFJ
DELF
JRST .+1
SETZM MBOT
MOVEI A,777
MOVEM A,MTOP
>
CLOSF2: SETZM MSGIDX
MOVE A,[MSGIDX,,MSGIDX+1]; Clean up index area
BLT A,MSGIDX+MSGIDN*1000-1
SETOM MSGIFJ
CLOSF1: SETZM MSGSEQ
SETOM MSGJFN
TOPS20< SKIPN A,MSGJF2 ; Is there a READ/WRITE JFN?
JRST CLOSF4 ; No
JUMPGE A,[ ; Yes, is the READ/WRITE file open?
RLJFN ; Release the JFN
JWARN (Cannot release the second JFN on the message file)
JRST CLOSF4 ]
TXZ A,RWJFNO ; Turn off the open bit
CLOSF ;
JWARN (Cannot close the second JFN on the message file)
CLOSF4: SETZM MSGJF2 > ; No more READ/WRITE JFN
TOPS10< SKIPLE A,MSGJF2 ;
CALL CLSJF2 ;
SETOM MSGJF2 > ;
TXZ F,F%AMOD!F%MOD ; Clear MOD hack bits
RET
;Unmap pages from file
TOPS20<
UNMAPF: SKIPN C,FILPGM
RET
SETO A,
HRRZ C,FILPGM
MOVE B,MSGPAG
HRLI B,.FHSLF
HRLI C,(PM%CNT)
PMAP
SETZM FILPGM
RET
>;End TOPS20
SUBTTL File parsing subroutines
GETFIL: CALL FNDFIL ; Try to find it first
RET ; Not there, forget it
TOPS10<
GETFLL:> ;
SKIPN FILSIZ ; Is the file empty?
JRST [ MOVE A,MSGJFN ; Yes, get JFN into A for message
TOPS20< SKIPN GTFLAG ; Message been typed already ?
CIETYP ( There are no messages in %1J.)
SETOM GTFLAG ; Say message has been typed
CALLRET CLOSEF] ;
>
TOPS10<
SKIPN GTFLAG ; Message been typed already ?
$TEXT (KBFTOR,<% There are no messages in ^F/MSGFD/>)
SETOM GTFLAG ; Say message has been typed
LSH A,^D23 ; Release message file channel
IOR A,[RELEASE]
XCT A
SETOM MSGJFN
RET]
>
TOPS20< CALL GETJF2 ; Open as READ/WRITE
CALLRET CLOSEF ; Couldn't, quit now
GETFLL:> ;
CALL SHRENQ ; Get shared ENQ on file
WARN (Can't lock message file)
SETZM UNSEEN ; New message file so no new messages
SETZM NDELET ; Or deleted
SETZM NFLAGD ; Or flaged
SETZ M, ; Must parse all messages
TOPS20< CALL PARSEF ;
CALLRET CLSJF2 > ; Close the READ/WRITE JFN
TOPS10< CALLRET PARSEF > ; And return
; Try to find a MAIL.TXT
FNDFIL:
TOPS20<
MOVE A,[POINT 7,STRBUF] ; Get string pointer
MOVEI B,[ASCIZ /POBOX:</]
CALL MOVSTR
MOVEI B,MYDIRS ; Login directory string
CALL MOVSTR
MOVEI B,[ASCIZ />MAIL.TXT.1/]
CALL MOVST0
MOVSI A,(GJ%OLD!GJ%SHT)
HRROI B,STRBUF
GTJFN
JRST FNDFL4
MOVEM A,MSGJFN ; Save the jfn away
HRROI A,MYSTR ; We need to save the structure
MOVE B,MSGJFN ; Get JFN back for MAIL.TXT
MOVX C,<FLD(.JSAOF,JS%DEV)+JS%PAF> ; We just want STR:
JFNS% ; Put STR: in appropriate place
ERJMP .+1 ; Don't care about errors
MOVE A,MSGJFN ; Get back JFN for MAIL.TXT to continue
CALL SIZFIL ; Before opening, to get last read correct
JRST CLOSEF ; Error message already printed
MOVE A,MSGJFN ; Get JFN back again
MOVEI B,OF%RD!OF%FDT ; Force read date/time update
OPENF
JRST FNDFL5
PUSH P,LASTRD ; Save last read date
CALL SIZFIL ; Re-check file size, now that it's open
IFNSK. ; No skip return is an error
POP P,LASTRD ; Restore stack
JRST CLOSEF ; And go close the file
ENDIF.
POP P,LASTRD ; Restore the last read date.
RETSKP ; Skip return
>;End TOPS20
TOPS10<
MOVEI A,MSGFD ; Message file FD
MOVEI B,FDXSIZ ; Size of FD
HRLZM B,.FDLEN(A) ; Store size
MOVE B,[SIXBIT /DSK/] ; Get structure for MAIL.TXT
MOVEM B,.FDSTR(A) ; ..
MOVE B,[SIXBIT /MAIL/]
MOVEM B,.FDNAM(A)
MOVE B,[SIXBIT /TXT/]
MOVEM B,.FDEXT(A)
MOVE C,MYDIR ; Point to my U-block
MOVE B,UB.PPN(C)
MOVEM B,.FDPPN(A)
CALL INILKB ; Init FILOP.'s LOOKUP/ENTER block
CALL FILOPR ; Open for read
JRST [ JUMPE A,R ; If not found, just quit
CALL FILERR ; Else type FILOP. error message
WARN <%Can't open message file>
RET]
MOVEM A,MSGJFN ; Save channel no. of message file
CALLRET SIZLKB ; Get FILSIZ, etc. from LOOKUP block
>;End TOPS10
TOPS20<
FNDFL4: SKIPG A,MSGJFN ; Get rid of stray jfns
JRST FNDFLX ; None, I guess...
RLJFN
JFCL
FNDFLX: SETOM MSGJFN
RET ; Return
FNDFL5: CAIN A,OPNX2 ; Empty file?
JRST FNDFL4 ; Yes - tread as non-ex
CITYPE <% Cannot open MAIL.TXT.1>
JRST FNDFL4
>;End TOPS20
TOPS10<
;INILKB - Init LOOKUP/ENTER block pointed to by FILOP. block
;Call: A/ address of FD for file
;Return +1: always
INILKB: HLRZ B,.FDLEN(A) ; Get length of this FD
CAIG B,.FDPPN+1 ; Is there room for an SFD spec?
JRST INILK1 ; No, don't fetch crud then
MOVE C,.FDPPN(A) ; Get PPN or path pointer
TLNN C,-1 ; Which flavor?
JRST INILK2 ; PPN, use it
SETZM PBLOCK ; Path, zero path block
MOVE C,[PBLOCK,,PBLOCK+1]
BLT C,PBLOCK+7 ; ..
HRLI C,.FDPPN(A) ; BLT the path block from the FD
HRRI C,PBLOCK+2 ; to out path block
ADDI B,PBLOCK+1-.FDPPN ; ..
BLT C,(B) ; ..
MOVEI C,PBLOCK ; Point lookup block at
MOVEM C,LKB+.RBPPN ; our path block
JRST INILK3
INILK1: MOVE C,.FDPPN(A) ; Move PPN
INILK2: MOVEM C,LKB+.RBPPN ; ..
INILK3: MOVE B,.FDNAM(A) ; Name
MOVEM B,LKB+.RBNAM ; ..
MOVE B,.FDEXT(A) ; Extension also clears access date
MOVEM B,LKB+.RBEXT ; and Hi order 3 bits of creation date
MOVEI B,7777 ; Clear low 12 bits of creation date
ANDCAM B,LKB+.RBPRV ; so it will not get reset
MOVE B,.FDSTR(A) ; Structure name
MOVEM B,MSGSTR ; Doesn't go in LOOKUP block
MOVEI B,.RBTIM ; Length of block
MOVEM B,LKB+.RBCNT ; ..
RET
;FILOPW - Open file for write (superseding)
;FILOPU - Open file for update, single-access
;FILOPR - Open file for read in multiple-access mode
;Call: with LKB inited
;Return +1: No channels left or file can't be opened
; +2: OK, with channel in A
FILOPW: MOVX A,.FOWRT ; Open for write only
JRST FILOP0
FILOPU: SKIPA A,[.FOSAU] ; Multiple access update
FILOPR: MOVX A,.FORED ; Read
FILOP0: HRRZM A,FILOPB+.FOFNC ; Stuff into FILOP. block
SETZM LKB+.RBSIZ ; Zero unused stuff in LOOKUP/ENTER block
MOVE B,[LKB+.RBSIZ,,LKB+.RBSIZ+1]
BLT B,LKB+.RBTIM
STKVAR <CHAN>
$CALL F%FCHN ; Get a free channel
JUMPF [ WARN <Can't open file, no free channels>
RET]
MOVEM A,CHAN ; Remember for later
HRLM A,FILOPB+.FOFNC ; Stuff into FILOP. block
MOVX A,.IODMP ; Dump mode
MOVEM A,FILOPB+.FOIOS ; ..
MOVE A,MSGSTR ; Structure name
MOVEM A,FILOPB+.FODEV ; ..
SETZM FILOPB+.FOBRH ; No buffers
SETZM FILOPB+.FONBF ; ..
MOVEI A,LKB ; Point to LOOKUP block
MOVEM A,FILOPB+.FOLEB
SETZM FILOPB+.FOPAT ; No paths supported yet
MOVE A,MYPPN ; Do access checking
MOVEM A,FILOPB+.FOPPN ; ..
MOVSI A,(1B0) ; Light bit saying "use privileges"
IORM A,FILOPB+.FOFNC ; ..
MOVE A,[.FOPPN+1,,FILOPB]
FILOP. A, ; Open the file
JRST [ EXCH A,CHAN ; Save error code, fetch channel
CALL CLSFIL ; Release this channel
MOVE A,CHAN ; Return error code to caller
RET] ; Failure return
MOVE A,CHAN ; Return channel to caller
RETSKP
;FILERR - Type error message corresponding to FILOP. failure
;Call with error code in A
FILERR: CALL CRIF ; Left margin please
CAIL A,ERFNF% ; Range check
CAILE A,ERJCH% ; ..
JRST FILER0
MOVE A,ERRTAB(A) ; Get ptr to appropriate error message
$TEXT (KBFTOR,<%File operation failed: ^Q/A/>)
RET
FILER0: $TEXT (KBFTOR,<%File operation failed: unknown FILOP. error ^O/A/>)
RET
SUBTTL SET/CLEAR the "new mail" bit
NEWMAL::SKIPG A,MSGJF2 ; Get secondary JFN
RET ; Quit if it's not open
HRLI A,.FORNM ; We are going to rename this puppy
TRO A,(FO.PRV!FO.UOC) ; Using the existing channel and our privs
MOVSM A,FILOPB+.FOFNC ; Set up function word for FILOP.
MOVE A,[LKB,,LKB+1]
SETZM LKB
BLT A,LKB+.RBTIM
MOVEI A,MSGFD ; Reinit the lookup block
CALL INILKB ; Which will be used as a RENAME block
SETZM LKB+.RBPPN ; Always use same path
SKIPE A,UNSEEN ; If there is unseen mail
MOVEI A,1 ; Set the "new mail" bit
MOVEM A,LKB+.RBFFB ; Set flag into new RIB word
MOVE A,[RB.DEC!FLD(.RBDAS,RB.DTY)!FLD(.RBOMS,RB.DTO)]
MOVEM A,LKB+.RBTYP ; Flag "DEC format", "ASCII data", "MS OTS"
MOVEI A,.IODMP ; Dump mode is as good as any
MOVEM A,FILOPB+.FOIOS ; for renaming a file
MOVE A,MSGSTR
MOVEM A,FILOPB+.FODEV
SETZM FILOPB+.FOBRH
SETZM FILOPB+.FONBF
MOVSI A,LKB ; Set up RENAME block pointer
MOVEM A,FILOPB+.FOLEB
SETZM FILOPB+.FOPAT ; No returned path
MOVE A,MYPPN ; Use my PPN for priv checking
MOVEM A,FILOPB+.FOPPN
MOVE A,[.FOPPN+1,,FILOPB]
FILOP. A, ; Try to rename the file away
JFCL ; Don't care if it fails
NEWMA1: MOVEI B,.FOREL
HRL B,MSGJF2
MOVE A,[1,,B]
FILOP. A, ; Release the channel
JFCL
RET
;LOOKUP/ENTER error message table
DEFINE ERRT(STRING),<
POINT 7,[ASCIZ |STRING|]
>
ERRTAB: ERRT <ERFNF% (0) - File not found>
ERRT <ERIPP% (1) - Nonexistent UFD>
ERRT <ERPRT% (2) - Protection failure>
ERRT <ERFBM% (3) - File being modified>
ERRT <ERAEF% (4) - File already exists>
ERRT <ERISU% (5) - Illegal sequence of monitor calls>
ERRT <ERTRN% (6) - Device or data error>
ERRT <ERNSF% (7) - Not a save file>
ERRT <ERNEC% (10) - Not enough core>
ERRT <ERDNA% (11) - Device not available>
ERRT <ERNSD% (12) - No such device>
ERRT <ERILU% (13) - Illegal monitor call>
ERRT <ERNRM% (14) - No room or quota exceeded>
ERRT <ERWLK% (15) - File structure is write-locked>
ERRT <ERNET% (16) - Insufficient monitor table space>
ERRT <ERPOA% (17) - Partial allocation only>
ERRT <ERBNF% (20) - Block not free on allocated position>
ERRT <ERCSD% (21) - Cannot supersede a directory>
ERRT <ERDNE% (22) - Cannot delete nonempty directory>
ERRT <ERSNF% (23) - SFD not found>
ERRT <ERSLE% (24) - Search list empty>
ERRT <ERLVL% (25) - SFDs nested too deeply>
ERRT <ERNCE% (26) - Can't create file on any structure in search list>
ERRT <ERSNS% (27) - GETSEG of nonexistent segment>
ERRT <ERFCU% (30) - Cannot update file>
ERRT <ERLOH% (31) - Page overlap error>
ERRT <ERNLI% (32) - Not logged in>
ERRT <ERENQ% (33) - File has ENQ locks outstanding>
ERRT <ERBED% (34) - Bad EXE file directory>
ERRT <ERBEE% (35) - File's extension is not EXE>
ERRT <ERDTB% (36) - EXE file directory too big>
ERRT <ERENC% (37) - Network capacity exceeded>
ERRT <ERTNA% (40) - Task not available>
ERRT <ERUNN% (41) - Unknown network node specified>
ERRT <ERSIU% (42) - SFD is in use (rename)>
ERRT <ERNDR% (43) - File has an NDR block>
ERRT <ERJCH% (44) - Job count too high (A.T. read count overflow)>
>;End TOPS10
SUBTTL File parsing subroutines - SIZFIL - Get size of current file
SIZFIL: STKVAR <SAVJFN,CHN0,<IOLIST,2>>
MOVEM A,SAVJFN ; Save JFN (or addr of FD)
TOPS10<
MOVE A,MSGJFN ; Get channel number
CALL APPNQ0 ; Get the append interlock
RETSKP ; Can't get it, don't change file size info
HRLZ B,MSGJFN ; Channel number for FILOP.
HRRI B,.FOUSI ; Set up useti function
SETZ C, ; to block 0 (prime RIB)
MOVE A,[2,,B]
FILOP. A, ; Position to read RIB
PJRST APPDEQ ; Failed, just release lock and return
HRRI B,.FOINP ; Function to read file (channel still in left)
MOVEI C,IOLIST ; point to iolist
MOVE A,[IOWD .RBMAX,LKB] ; Read into standard place
MOVEM A,(C)
SETZM 1(C)
MOVE A,[2,,B]
FILOP. A, ;Read the first part of the RIB
PJRST APPDEQ ;Failed, just release lock and return
CALL APPDEQ ;Release append lock now
SIZLKB: MOVE A,LKB+.RBSIZ ; Get word count for file
IMULI A,5 ; Form byte count
SIZEXP: MOVEM A,FILSIZ ; Save number of bytes
ADDI A,BY2PAG-1 ; Round up
IDIVI A,BY2PAG ; ..
MOVEM A,FILPGS ; and pages (blocks)
MOVE A,LKB+.RBTIM ; Get creation date/time
MOVEM A,FILCRV ; Store
MOVEM A,FILWRT ; TOPS10 doesn't offer append date
RETSKP
>;End TOPS10
;(TOPS20 portion on next page)
;SIZFIL - (Fall through from previous page)
TOPS20<
MOVE U,FILSIZ ; Save the old file size for comparison
MOVE B,[5,,.FBBYV]
MOVEI C,FILPGS
GTFDB ; Get the size stuff
ERJMP [JRETER (GTFDB failed on message file)
RET]
SETZM CHNSIZ ; Assume no change in file size
REPEAT 0,<
TXNN F,F%MOD ; MOD wanted
IFSKP. ; Skip means MOD is set
SETO A, ; Yes - get d/t last login then
HRROI B,D
MOVEI C,.JILLN ; For this job
GETJI ; Instead of d/t last read
SETZ D, ; use 0 if can't obtain it
MOVEM D,LASTRD ; Save it as last read
ENDIF.
>
CAME U,FILSIZ ; Compare latest file size with previous
SETOM CHNSIZ ; A change in size occurred
LDB U,[POINT 6,FILPGS,11] ; Get byte size
MOVE V,FILSIZ ; Else get the size now
CAIN U,7 ; If 7 bit,
JRST SIZFL3 ; Are almost done
CAIN U,^D36 ; 36 bit is easier
JRST SIZFL2
MOVEI T,^D36
IDIVI T,(U) ; Get number of bytes in a word
IDIVI V,(T) ; Get number of words
SIZFL2: IMULI V,5 ; Into bytes
SIZFL3: MOVEM V,FILSIZ ; Save the size
IDIVI V,BY2PAG ; Since we may have the file open, the
SKIPE V+1 ; Page count may be too little
AOJ V, ; So, we must check against the
HRRZ T,FILPGS ; Size according to the byte count
MOVE A,SAVJFN ; Else - try to find first free page
GTSTS ; Only do this if file open
TXNN B,GS%OPN
IFNSK. ; No skip, file isn't open
CAMLE V,T ; Use smaller page count,
MOVE V,T ; to prevent illegal memory reads
HRRM V,FILPGS ; ..
RETSKP
ENDIF. ;
FFFFP ; Look for first free page
JFCL ; Check error in a second
HRRZ B,A ; Save this page number
CAMGE B,V ; Is first free page before EOF?
IFNSK. ; Yes, it is
MOVE V,B ; Keep that as the EOF page count
HRL A,SAVJFN ; Get JFN back
FFUFP% ; See if there are any other used pages
JFCL ; This JSYS skip returns
HRRZS A ; Clear JFN
CAIN A,FFUFX3 ; No used page found?
IFSKP. ; None found, this is real page count
HRRZS A ; Clear jfn from LH
WARN <File has bad format - missing pages %2D thru %1D>
WARN <MS cannot parse messages beyond this hole.>
CALL CRLF ; Finish line
MOVE A,B ; Set up the right page count for later
ENDIF. ;
ENDIF. ; Otherwise...
HRRM V,FILPGS ; Save the real page count again
IMULI V,BY2PAG ; Compute byte count
CAMGE V,FILSIZ ; If FDB byte count too big,
MOVEM V,FILSIZ ; prevent ill mem reads in PARSEF
RETSKP
>;End TOPS20
SUBTTL File parsing subroutines - PARSEF - Parse the file from message (M) on
PARSEF:
TOPS20< CALL UNMAPF ; Get rid of unwanted pages (We need this here)
SKIPN CHNSIZ ; Has size of the file changed?
JRST NOTFRT ; No, so do not do a total reparse
SETZ M, ; Reparse the entire file
MOVEI B,MSGIDX ; Address of the index area
ASH B,^D-9 ; Change to its page number
HRLI B,.FHSLF ; Unmap for this process
MOVEI C,MSGIDN ; Number of pages to unmap
HRLI C,(PM%CNT) ;
SETOM A ; Indicate want to unmap pages
PMAP
ERJMP [WARN (Can not unmap the index file)
RET]
NOTFRT: > ;End of TOPS20
JUMPN M,PARSF1 ; We aren't started from the beginning
SETZ V, ; starting at first page
JRST PARSF2 ; And go map it all in
PARSF1: SOS M
GTMBL (M,T) ; Pointer to msg block for last msg
AOS M
MOVE V,MSGALL(T) ; Get start of last msg
ADD V,MSGALN(T) ; Move to start of next message
PARSF2: CALL RMP1 ; Map the messages into the window
;Here after reading a new chunk of message file - parse new stuff
;
; D/ Real start of first header line of the message
; M/ Current message number
; T/ Address of message index block (from GTMBL)
; V/ Current character position while scanning
; W/ -1 if garbage precedes this message, 0 otherwise
PARS10:
IFN MHACK,< ; If using BLISS parser,
CHR2BP ; Convert to byte pointer
PUSH P,A ; Push arg 1
MOVE A,MSGFAD ; Address of message buffer
IMULI A,5 ; Byte address of buffer
SUB V,A ; Compute number of bytes already parsed
MOVE A,FILSIZ ; Get size of file in bytes
SUB A,V ; Compute bytes left unparsed
PUSH P,A ; Push arg 2
CALL PARSE%## ; Go parse remaining messages
ADJSP P,-2 ; Pop args from stack
RET ; and return
>;End IFN MHACK
IFE MHACK,< ; Old code
GTMBL (M,T) ; Get next message index block
MOVEM V,MSGALL(T) ; Start of whole message
SETZB W,MSGBTS(T) ; Invalidate this index block until parsed.
MOVE D,V ; Remember the alleged start of this message
JRST PARS12 ; Lets find out
;
; Here to parse the message header line preceding the message body
;
PARS11: MOVE D,V ; Remember the real start of this message
SETO W, ; And flag that there is garbage in front
PARS12: CAML V,FILSIZ ; Check for EOF
JRST FILEOF ; All done, punt
CALL GTBFL ; Get character FROM THE FILE
AOS V ; Bump character position
CAIE A,.CHLFD ; Carriage return?
SKIPN A ; Null?
JRST PARS11 ; Get next line
CAIE A,"," ; Look for a comma
JRST PARS12 ; Not a comma, keep looking
MOVEI C,^D10 ; Decimal
CALL .NIN ; Read the length field
CAIE A,";" ; Genuine count, and not some random number?
JRST PARS11 ; Go get next line
MOVEM B,MSGBON(T) ; Save alleged length of message
MOVEI C,10 ; Octal
CALL .NIN ; Get the message bits
CAIE A,.CHCRT ; Better be terminated with CR
JRST PARS11 ; Go get next line
HRRZM B,MSGBTS(T) ; Save message bits in dynamic part
HRLM B,MSGBTS(T) ; And save the "in file" part
TRNN B,M%SEEN ; Is this message new?
AOS UNSEEN ; Yes, increment count
TRNE B,M%DELE ; Is this message deleted?
AOS NDELET ; Yep, add to the number deleted
TRNE B,M%ATTN ; Is this message flagged?
AOS NFLAGD ; Uh huh, remember another one
CAML V,FILSIZ ; Check for EOF
JRST FILEOF ; And punt
CALL GTBFL ; Get the next character
AOS V ; Bump character position
CAIE A,.CHLFD ; Is this a linefeed?
JRST PARS11 ; Go get next line
SKIPN W ; Any bad characters to add to previous message?
IFSKP. ; Skip means there are, so
MOVEM D,MSGALL(T) ; Save the real starting position of the message
PUSH P,T ; Save the message block index
SOSL M ; Go back one message
IFSKP. ; Skip means we haven't seen any messages yet.
WARN <File has bad format - First message is preceded by junk>
$CALL K%FLSH ; Flush output
JRST PARS14 ; Set back to first message
ENDIF. ; Rejoin message fix-up code
GTMBL (M,T) ; Get index of previous message
MOVE B,D ; Copy start of current message
SUB B,MSGALL(T) ; Calculate distance from previous message
MOVEM B,MSGALN(T) ; Save it
MOVE B,D ; Get the start of current message again
SUB B,MSGBOD(T) ; Calculate distance from prev. msg. body
MOVEM B,MSGBON(T) ; Save it too
PARS14: AOS M ; Bump message number back up
POP P,T ; Restore the message block index
ENDIF.
MOVEM V,MSGBOD(T) ; Save start of real message
MOVE A,V ; Start of real message
MOVE B,MSGBON(T) ; Get the alleged length
ADD A,B ; Add alleged length
CAMG A,FILSIZ ; Does that go beyond the known file length?
IFSKP. ; Skip means we have to adjust message length
WARN <Last message has invalid length field, truncating.>
WARN <Any new messages will cause file damage.>
WARN <DELETE or MOVE last message to correct this problem.>
$CALL K%FLSH ; Flush output
MOVE A,FILSIZ ; Get the file length
SUB A,V ; Calculate the real message length
MOVEM A,MSGBON(T) ; And save it again
MOVE A,FILSIZ ; This is now the end of this message
ENDIF. ; and continue
PUSH P,A ; Save it for later
MOVE B,MSGALL(T) ; Where it started
SUB A,B ; Length of whole thing
MOVEM M,MSGNUM(T) ; Save message number
MOVEM A,MSGALN(T) ; Save it too
MOVE A,MSGBTS(T) ; Get message bits
TRNN A,M%ATTN ; Flagged?
TRNN A,M%SEEN ; or not seen?
CALL PRSMS0 ; Yes to either, parse msg and flag valid
TOPS20<
POP P,V ; Recover ending address
CAMGE V,FILSIZ ; See if EOF yet
AOJA M,PARS10 ;no, keep going
>
TOPS10<
MOVE V,FILSIZ ;Get size of file
SUB V,(P) ; Calculate bytes remaining
CAIGE V,5 ; Less than 5? (one word's worth)
JRST PARS15 ; Yes, we're effectively done.
POP P,V ; Got 5 or more chars left
AOJA M,PARS10 ; So keep going
PARS15: POP P,V ; Restore last address either way
>
PARSEX: MOVEM M,LASTM ;STORE MESSAGES COUNT
RET
; FILEOF - End of file error recovery
;
; Called with:
; V/ Current position in file
; T/ Address of message index block for current message
; M/ Current message number
;
; Returns:
; +1 - End of file, M/ previous msg, T/ previous msg index block
; +2 - Not end of file
FILEOF: SETZM MSGALL(T) ; Clear this index block
SOSL M ; Back up one message
IFSKP. ; Skip if that was the first message
WARN <File has bad format - no messages found.>
$CALL K%FLSH ; Flush output
SETZ M, ; Reset message number
RET ; And punt
ENDIF. ;
WARN <File has bad format - cannot find start of last message.>
WARN <DELETE or MOVE last message to correct this problem.>
$CALL K%FLSH ; Flush output
GTMBL (M,T) ; Get index block for that message
MOVE A,FILSIZ ; Get EOF mark
SUB A,MSGALL(T) ; Calculate real length
MOVEM A,MSGALN(T) ; Save it
MOVE A,FILSIZ ; Get EOF again
SUB A,MSGBOD(T) ; Calculate length of message body
MOVEM A,MSGBON(T) ; Save it too.
JRST PARSEX ; And punt
; (Still inside IFE MHACK)
SUBTTL File parsing subroutines - PRSMSG, PRSMS0 - parse single message
;PRSMSG - Parse a single message, preserving all temp ACs
;PRSMS0 - Parse message for code willing to have ACs stomped on
PRSMSG: $SAVE <A,B,C,D,E> ; For sensitive callers
PRSMS0: PUSH P,M ; Save M as msg number
GTMBL (M,MX) ; Get ptr to message block
MOVE V,MSGBOD(MX) ; Get beginning of message body
MOVE W,MSGBON(MX) ; Get size of whole message
CALL SETSFL ; Set stuff for file searching
MOVE A,MSGFAD ; Correct char pointer
IMULI A,5
ADD V,A
SUB V,WBOT
MOVEI T,[ASCIZ /
/] ; Search for end of header area (2 CRLFs)
CALL SSEARC
JRST [ MOVE W,MSGBON(MX) ; Not found, assume whole msg
MOVEM W,MSGHDN(MX) ; is one big header
JRST PRSMS1] ; ..
BP2CHR ;CONVERT BYTE POINTER
ADD V,WBOT
MOVE B,MSGFAD ;TO CHAR POINTER
IMULI B,5 ;FROM THE BEGINNING
SUB V,B ;OF THE FILE
SUB V,MSGBOD(MX) ; Compute length of header area
MOVEM V,MSGHDN(MX) ; and save it away
PRSMS1: MOVX A,M%VALI ; Flag that this msg has valid info
IORM A,MSGBTS(MX) ; ..
CALL FNDSUB ; Find the subject
MOVEM V,MSGSUB(MX)
MOVEM W,MSGSUN(MX) ; Save position and size
CALL FNDSND ; Find sender
MOVEM V,MSGSND(MX)
MOVEM W,MSGSNN(MX)
CALL FNDFRM ; Find the from
MOVEM V,MSGFRM(MX) ; Where
MOVEM W,MSGFRN(MX) ; Size
CALL FNDTO ; Find "to" list
MOVEM V,MSGTO(MX) ; Where
MOVEM W,MSGTON(MX) ; Size of first line
MOVEM X,MSGTOK(MX) ; Size of entire field
CALL FNDCC
MOVEM V,MSGCC(MX) ; Find Carbon-copy
MOVEM X,MSGCCN(MX)
CALL FNDMID ; Find message-ID
MOVEM V,MSGMID(MX)
MOVEM X,MSGMIN(MX)
CALL FNDREF ; Find Reference
MOVEM V,MSGREF(MX)
MOVEM X,MSGRFN(MX)
CALL FNDRRR ; Return receipt requested
MOVEM V,MSGRRR(MX)
MOVEM W,MSGRRN(MX)
CALL FNDDAT ; Find the date
MOVEM B,MSGDAT(MX) ; Receive date
AOJN B,PRSMS2 ; Not found (ie., -1)?
CALL FNDSDT ; Yes, try for send date then
MOVEM B,MSGDAT(MX) ; ..
PRSMS2: MOVE V,MSGBOD(MX) ; Get character pointer
SUB V,WBOT
MOVE A,MSGFAD
IMULI A,5
ADD V,A
CHR2BP ; Form byte pointer
POP P,M ; Restore M as msg number
RET ; All done!
>;End IFE MHACK
IFE MHACK,<
;.NIN - Parse a number pointed to by V (IN FILE ), radix in C
.NIN: SETZ B,
.NIN1: CALL GTBFL ; Get char from file
AOS V
CAML V,FILSIZ ; Do we fall off the edge of the world
JRST .NIN2 ; Explain this one to the queen
CAIL A,"0"
CAILE A,"0"-1(C)
RET ; Done
IMULI B,(C)
ADDI B,-"0"(A)
JRST .NIN1
.NIN2: POP P,A ; Remove return address off of stack
JRST FILEOF ; and move on to EOF recovery
;Check to see if byte pointer in A has gone past EOF
;Return +1: No, byte pointer is OK
; +2: Yes, you've run off the end
CHKEOF: BP2CHR ; Convert to character pointer
CHKEF0: MOVE B,MSGFAD ; Word address of 1st word in file
IMULI B,5 ; Byte address of 1st byte
MOVE C,V ; Don't clobber V
SUB C,B ; Compute byte offset into file
CAMGE C,FILSIZ ; Off the end yet?
RET ; No, nonskip
RETSKP ; Yes, skip
>;End IFE MHACK
SUBTTL UPDBIT - update the file copy of the message bits
UPDBIT: STKVAR <IOWDT,BLKNO,BTPTR,MBITS,BLINC,WRTPGS>
GTMBL (M,B) ; Get ptr to message block
LDB A,[POINT 12,MSGBTS(B),17]
HRRZ B,MSGBTS(B) ; Get new copy of bits
MOVEM B,MBITS ; Save in case CHECKS and PARSEF clobber
TXNN F,F%MOD ; MOD hack - exit now
CAIN B,(A) ; Old matches new?
RET ; Yes, no need to do any more
CALL CTCLOK ; ENQ for exclusive access
JRST [ WARN <Can't update message bits -- another reader exists>
CALL CRIF ;
RET]
CALL GETJF3 ; Get a second jfn if dont already
CALLRET CTCOK ; Error, try to reenable CTRL-C
SETZM WRTPGS ; No update I/O buffer yet
TOPS10< MOVEI A,400 ; Need 2 blocks for I/O (in case msg bits cross
$CALL M%GMEM ; page boundary)
JUMPF UPDBTM ; Memory allocation error
MOVEM B,WRTPGS ; Save address of buffer
>
TOPS20< MOVEI A,2 ; Need 2 pages for I/O (in case msg bits cross
$CALL M%AQNP ; page boundary)
JUMPF UPDBTM ; Insufficient memory
LSH A,^D9 ; Convert page number to address
MOVEM A,WRTPGS ; Save address of buffer
>
GTMBL (M,B) ; Get ptr to message block
MOVE V,MSGALL(B) ; Start of the message header
CALL SETSFL
PUSH P,V
SUB V,WBOT
MOVE A,MSGFAD
IMULI A,5
ADD V,A
CHR2BP ; Get byte pointer
POP P,V
UPDBT1: ILDB B,A ; Get char
CAIN B,15 ; At end of line??
JRST [ CMERR (File has bad format - Cannot find message flags)
JRST UPDBTX]
CAIE B,";" ; At start of bits?
JRST UPDBT1
SUB A,MSGFAD ; Get relative pointer
MOVEM A,BTPTR ; Save that pointer
HLRZ B,A
CAIN B,010700
AOJ A,
ANDI A,-1
TOPS20< MOVE C,WBOT ; Window displacement
IDIVI C,5000
IDIVI A,1000 ; Get page number we need
ADD A,C
HRL A,MSGJF2
CAIL B,775 ; If near end of page
SKIPA C,[PM%CNT+PM%WR+PM%RD+2] ; Map two pages
MOVSI C,(PM%WR!PM%RD)
MOVE B,WRTPGS ; Address of buffer
LSH B,-^D9 ; Convert to page number
HRLI B,.FHSLF ; This fork
PMAP
>;End TOPS20
TOPS10< MOVE B,WBOT ; Starting byte of the window
IDIVI B,5 ; Convert to words
ADD A,B ; Words from start of file
IDIVI A,200 ; Get block number minus one
MOVEI A,1(A) ; Correct block number
MOVEM A,BLKNO ; Save for later
MOVE C,MSGJFN ; Get channel for message file
LSH C,^D23 ; Move to AC field
IOR C,[USETI] ; Get instruction
HRR C,BLKNO ; Get correct block number
XCT C ; Point to it
MOVE A,WRTPGS ; Get address of buffer
SUBI A,1 ; minus one (for IOWD)
HRLI A,-200 ; Assume only one block of I/O
CAIL B,175 ; Need to read two blocks?
HRLI A,-400 ; Yes, get bigger word count
MOVEM A,IOWDT ; Save for later
MOVEM A,MSIOWD ; and save in place for IN UUO
SETZM MSIOWD+1 ; Tie off list
MOVE A,MSGJFN ; Get channel back
LSH A,^D23 ; Put in right place
IOR A,[IN MSIOWD] ; Form instruction to read stuff
XCT A ; Snarf
SKIPA ; Good stuff
FATAL (Can't read message file to update bits)
>;End TOPS10
MOVE A,BTPTR ; Get back byte pointer
TOPS20< TRZ A,777000 > ; Just relative to page
TOPS10< TRZ A,777600 > ; Just relative to block
ADD A,WRTPGS ; Offset right
MOVEM A,UPDPTR ; Save pointer for TOR
MOVE B,MBITS ; Bits to write to file
$TEXT (UPDBT9,<^O12R0/B/^A>) ; 12 digits, zero-filled, right-justified
GTMBL (M,A) ; Get ptr to message block
DPB B,[POINT 12,MSGBTS(A),17] ; This is now the file version
TOPS20<
SETO A,
MOVE B,WRTPGS ; Get address of buffer
LSH B,-^D9 ; Form page number
HRLI B,.FHSLF ; This fork
MOVE C,[PM%CNT+2]
PMAP ; Unmap the pages
JRST UPDBTX ; Clean up and return
>;End TOPS20
TOPS10<
GTMBL (M,A) ; Get ptr to message block
HRRM B,MSGBTS(A) ; In case GETJF3/CHECKS/GET1 wiped these out
MOVE A,BTPTR ; Must also update in-core version
ADD A,MSGFAD ; ..
MOVEM A,UPDPTR ; of file bits because TOPS10 can't map
$TEXT (UPDBT9,<^O12R0/B/^A>) ; 12 digits, zero-filled, right-justified
SETZM BLINC ; Init block increment to zero
HLRZ A,IOWDT ; Get count part of IOWD used to read block(s)
MOVE B,BLKNO ; Get first block number read
CAIN A,-400 ; Did we read two blocks?
JRST [MOVEI C,200 ; Yes, set block increment
MOVEM C,BLINC ; up by 1 block (200 words)
ADDI B,1 ; Bump number of last block read
JRST .+1] ; Continue
MOVE C,FILSIZ ; Get number of bytes in file
ADDI C,BY2PAG-1 ; Cause roundup
IDIVI C,BY2PAG ; Compute "pages" (blocks) in file
MOVE A,IOWDT ; Get original IOWD back
CAIN C,(B) ; Did we diddle last block of file?
JRST [MOVE C,FILSIZ ; Yes, get file size back
ADDI C,4 ; Force roundup
IDIVI C,5 ; Compute word length of file
ANDI C,177 ; Drop block no. part of length
SKIPN C ; Is last block completely filled?
MOVEI C,200 ; Yes, write whole block
ADD C,BLINC ; Account for possibility of 2 blocks
MOVN C,C ; Form new word count
HRL A,C ; Fix up IOWD
JRST .+1]
MOVEM A,MSIOWD ; Save IOWD
SETZM MSIOWD+1
MOVE A,MSGJF2 ; Get channel number to write on
LSH A,^D23 ; Put in AC field
TLO A,(USETO) ; Form USETO instruction
HRR A,BLKNO ; Where to point
XCT A ; Get there
TLC A,(<OUT >^!<USETO >); Change to OUT instruction
HRRI A,MSIOWD ; Point to IOWD
XCT A ; Write updated blocks
JRST UPDBTX ; Success, clean up and return
FATAL (Can't update message bits)
CALL CRIF ;
>;End TOPS10
;Here on normal return
UPDBTX:
TOPS10<
MOVEI A,400 ; Release buffer space
MOVE B,WRTPGS ; ..
$CALL M%RMEM ; ..
CALLRET CLSJF2 ; Unlock and close file and return
>;End TOPS10
TOPS20<
MOVEI A,2 ; Release buffer pages
MOVE B,WRTPGS ; Address
LSH B,-^D9 ; Form page number
$CALL M%RLNP ; Release 'em
CALLRET CLSJF2 ; Unlock and close file and return
>;End TOPS20
;Here on memory allocation failure
UPDBTM: WARN <Can't update message bits because: insufficient memory>
CALL CRIF ;
CALLRET CLSJF2
;Here from $TEXT macro above to write messge bit digits
UPDBT9: JUMPE A,[$RET] ; Don't write nulls
CAIE A,15 ; Don't do CR or LF either
CAIN A,12 ; ..
$RET ; ..
IDPB A,UPDPTR ; Store where UPDPTR tells us to
$RET
CLSJF2:
TOPS10< MOVE A,MSGJF2> ;
TOPS20< HRRZ A,MSGJF2 ;
TXNE F,F%MOD ; MOD?
JRST CLSJ2A ; Yes, just close the file
SIZEF ; Get page count for file
ERJMP [JRETER <SIZEF failure for message file>
HRRZ A,MSGJF2 ; at least try to close it
JRST CLSJ2A]
HRLZS A ; JFN ,, start at page zero
MOVEI B,(C) ; Count of pages to update
UFPGS
ERJMP [JRETER <UFPGS failure for message file>
JRST .+1]
HRRZ A,MSGJF2 ; Get JFN back
CLSJ2A: TXO A,CO%NRJ ; Keep this JFN around
CLOSF
ERJMP [ CAIN A,CLSX1 ; Already closed?
JRST CLSJ2B ; Yes,
JWARN (Cannot close second JFN on message file)
JRST CLSJ2C] ;
CLSJ2B: HRRZ A,MSGJF2 ; In case error , get JFN again
MOVEM A,MSGJF2 ; JFN, but now closed
CLSJ2C: CALL SETREF ; Set read date-time
>;End TOPS20
TOPS10< CALL NEWMAL
SETOM MSGJF2
>
CALL CTCOK ; Allow ctrl-C again if disabled
RET ; Done
TOPS20<
RELJF2: HRRZ A,MSGJF2
RLJFN ; release JFN
JFCL ; Maybe error?
SETZM MSGJF2 ; No longer have one
RET
CLWJFN: HRRZ A,MSGJF2 ; Pick up the READ/WRITE JFN
TXO A,CO%NRJ ; Don't release it
CLOSF ;
JRST [ WARN (Cannot close the second JFN of the message file)
RET]
HRRZ A,MSGJF2 ; Pick up the READ/WRITE JFN
MOVEM A,MSGJF2 ; Save updated status
RET ;
CJFNS: CLOSF ; Close it
WARN (Cannot close JFN on the new message file)
SKIPN A,GTJFN2 ; Is there a second JFN?
RET ; No
CLOSF ; Yes, Close it
JRST [ CAIN A,CLSX1!DESX3 ; File already closed or JFN not
JRST CJFNS2 ; assigned? Yes
WARN (Cannot close second JFN on the new message file)
RET] ;
CJFNS2: SETZM GTJFN2 ; No longer have a JFN
RET ;
>;End TOPS20
;GETJF2 - Open message file for write (expunge)
;GETJF3 - Open for update (UPDBIT)
;
;(These two routines are the same on TOPS20, but differ on TOPS10)
TOPS10<
GETJF2: MOVEI A,MSGFD ; Init LOOKUP/ENTER block
CALL INILKB ; ..
MOVE A,MSGJFN ; Get open channel number
MOVEM A,PBLOCK ; Stuff into path block
MOVE A,[10,,PBLOCK] ; Set up to read path
HRRZM A,LKB+.RBPPN ; Point to path block for opening write file
PATH. A, ; to be the same as currently open mail file
JFCL
CALL FILOPW ; Open message file for write
JRST [ CALL FILERR ; Type FILOP. error string
WARN <Second open on message file failed>
RET]
MOVEM A,MSGJF2 ; Remember channel
CALL CHECK0 ; Any new messages pending?
JRST RSKP ; No, all set then
MOVE A,MSGJF2 ; Yes, recover channel number
RESDV. A, ; Abort this opening
FATAL <Can't abort second opening of message file>
SETOM MSGJF2 ; Leave tracks
CALL CHECKS ; Read and parse new mail
JRST GETJF2 ; Now try again
GETJF3: MOVEI A,MSGFD ; Init LOOKUP/ENTER block
CALL INILKB ; ..
CALL FILOPU ; Open message file for update
JRST [ CALL FILERR ; Type FILOP. error string
WARN <Second open on message file failed>
RET]
MOVEM A,MSGJF2 ; Remember channel
CALL CHECK0 ; Any new messages pending?
JRST RSKP ; No, all set then
MOVE A,MSGJF2 ; Yes, recover channel number
RESDV. A, ; Abort this opening
FATAL <Can't abort second opening of message file>
SETOM MSGJF2 ; Leave tracks
CALL CHECKS ; Read and parse new mail
JRST GETJF3 ; Now try again
;Utility routine to close and release a channel in A
CLSFIL: LSH A,^D23
IOR A,[CLOSE]
XCT A
TLC A,(<CLOSE >^!<RELEASE>)
XCT A
RET
>;End TOPS10
TOPS20<
GETJF2:
GETJF3: SKIPE MSGJF2 ; Have one already?
JRST GETJ2A ; Yes, use it
HRROI A,STRBUF
MOVE B,MSGJFN ; One we do have
SETZ C,
JFNS
MOVSI A,(GJ%OLD!GJ%SHT)
HRROI B,STRBUF
GTJFN
ERJMP [JRETER (Cannot get second JFN on file)
RET]
MOVEM A,MSGJF2 ; Save jfn
MOVEI D,MS%ISA ; Number of attempts on Inv. simul. access
GETJ2A: SKIPG A,MSGJF2 ; Is the file open?
RETSKP ; Yes, so return
MOVX B,7B5+OF%RD!OF%WR!OF%PDT ; Open file for write as well (it is
OPENF ; now write-locked against new msgs).
ERJMP CHEKIT ; Check the error
MOVE A,MSGJF2 ; Pick up the READ/WRITE JFN
TXO A,RWJFNO ; Mark as open
MOVEM A,MSGJF2 ; Save the updated status
RETSKP ; Return success
CHEKIT: SOSL D ; Have we done this enough times?
JRST CHKIT1 ; Yes, return error this time
CAIN A,OPNX9 ; Invalid simultaneous access?
JRST SIMULT ; Yes, pause, and retry
CHKIT1: JRETER <Can't update message file - >
RET
SIMULT: MOVEI A,^D1000 ; Sleep for 1 second
DISMS% ; Zzzzzzzzz.....
MOVE A,MSGJF2 ; Recapture the JFN
JRST GETJ2A ; Try to open it again
GTSJFN: HRROI A,JF2BUF ; Point to where to put the file name
SETZ C, ; No format control bits
JFNS ; Get the file spec
ERJMP [ JRETER (Cannot get file specification on file)
RET]
MOVSI A,(GJ%OLD!GJ%SHT) ;
HRROI B,JF2BUF ; Point to the file spec
GTJFN ; Get the second JFN
ERJMP [ JRETER (Cannot get second JFN on file)
SETZM GTJFN2 ;
RET] ;
MOVEM A,GTJFN2 ; Save the READ/WRITE JFN
MOVX B,7B5+OF%RD!OF%WR!OF%PDT ; Yes, Open for READ only
TXNE F,F%MOD ; MOD turned on?
MOVX B,7B5+OF%RD!OF%PDT ; Open for READ/WRITE
OPENF ;
ERJMP [ JRETER <Can't update message file>
MOVE A,GTJFN2 ; Get the READ/WRITE JFN
RLJFN ; And release it
JFCL ;
SETZM GTJFN2 ;
RET] ;
MOVE A,GTJFN2 ; Get the READ/WRITE JFN
TXO A,RWJFNO ; Mark as open
MOVEM A,GTJFN2 ; Save the updated status
RETSKP ;
>;End TOPS20
;This routine gets a byte from the mapped mail file
; V/ character pointer (from file start)
;on return A/byte
GTBFL:: PUSH P,B
CAML V,WBOT ;LESS THAN WINDOW BOTTOM
CAMLE V,WTOP ;OR MORE THAN WINDOW TOP
CALL REMAP ;YES, REMAP
MOVE A,V
SUB A,WBOT ;OFFSET IN THE WINDOW
IDIVI A,5 ;IN WORDS
ADD A,MSGFAD
ADD A,[ POINT 7,0,6 ;MAKE THE BYTE POINTER
POINT 7,0,13
POINT 7,0,20
POINT 7,0,27
POINT 7,0,34](B)
LDB A,A
POP P,B
RET ;DONE
;REMAPS FILE V -REFERENCE ADDRESS
;PAGE CONTAINING (V) GOES TO THE TOP OF THE WINDOW
; Possible enhancement: always fill window as much as possible. i.e. don't
; read just the last few pages in
REMAP:: MOVE A,V ; Character pointer
SUB A,WBOT ; Are we already mapped into the
JUMPL A,RMP1 ; first page of
CAIG A,777 ; the window?
RET ; Yes, they were probably just testing us then
RMP1: SKIPL V ; If byte count is illegal
CAMLE V,FILSIZ ; Protest
$STOP (CPR, Character Pointer Out of Range)
$SAVE <B,C,D,E> ; Save away some ACs
TOPS20< CALL UNMAPF ; Tops-20 feels a need to let go of these pages
MOVE A,V ; Char number
IDIVI A,BY2PAG ; File page/block number
PUSH P,A ; Store it
HRRZ B,FILPGS ; Total pages in file
SUB B,A ; How many left
MOVE C,WWIDH ; Window size
CAMGE B,C ; Left more than window can hold ?
MOVE C,B ; No, take as many as nessesary
MOVEM C,FILPGM ; Store it
HRL A,MSGJFN ; And jfn
MOVE B,MSGPAG ; Mapping place
HRLI B,.FHSLF ; Our fork
HRLI C,(PM%CNT!PM%RD!PM%CPY!PM%PLD) ; Start the I/O now, please
PMAP
MOVE C,FILPGM ; Restore stuff
POP P,A
IMULI A,BY2PAG ;CALCULATE WINDOW FRAME
MOVEM A,WBOT ;STORE IT
IMULI C,BY2PAG
SUBI C,1
ADD C,A
CAMLE C,FILSIZ
MOVE C,FILSIZ
MOVEM C,WTOP
RET
>;End TOPS20
TOPS10< MOVEI A,.FOUSI ; FILOP function USETI
HRL A,MSGJFN ; Channel number
MOVE B,V ; Char number
IDIVI B,BY2PAG ; File block number
AOS B ; Round up
MOVE C,[2,,A] ; Length and address
FILOP. C, ; Point file at block with V
$STOP (UOB, USETI Out of Bounds)
HRRI A,.FOINP ; Next FILOP. will be an INPUT
SOS B ; Get back to blocks, numbering from zero
IMULI B,BY2PAG ; Convert blocks to bytes
MOVEM B,WBOT ; This will be the bottom of the window
MOVE C,FILSIZ ; Size of the file in bytes
SUB C,B ; Number of bytes left in the file
MOVE D,WWIDH ; Number of PAGES window is long
IMULI D,5000 ; Which is this many bytes
CAMGE C,D ; We want the smaller of the two
MOVE D,C ; ...
MOVEM D,FILPGM ; Save the number of in core bytes
ADD B,D ; Last byte in core
SOS B ; OFF BY ONE
MOVEM B,WTOP ; Which is the top of the window
IDIVI D,5 ; Convert bytes to words
MOVN C,D
HRLZ C,C
MOVEI D,MSGA1
SOS D
MOVEI B,C
HRR C,D
SETZ D,
MOVE E,[2,,A]
FILOP. E,
$STOP (ERF, Error Reading File)
RET
>
; ROUTINE RETURNS A MESSAGE BLOCK POINTER IN THE SPECIFIED REGISTER
; CALL : JSP F,GTMBL
; MESSAGE NUMBER ADRESS,,BLOCK ADRESS
; USE THE MACRO GTMBL
GTMIND::DMOVEM A,IDXSAV ; Save AC's
MOVEM C,IDXSAV+2 ;
HLRZ A,(F) ;SOURCE ADRESS
CAIN A,A ;A ITSELF ?
SKIPA A,IDXSAV ;YES, RESTORE
MOVE A,(A) ;MESSAGE NUMBER
CAMG A,MTOP ;Is the message number above the top?
CAMGE A,MBOT ; is it below the lowest mapped index block?
CALL MMAP ; Call the routine to map the index window
TRZ A,777000 ;OFFSET IN THE WINDOW
IMULI A,MSGIDN ;IN WORDS
ADDI A,MSGIDX ;PLUS REAL WINDOW TOP
HRRZ B,(F) ;DESTINATION ADRESS
CAIL B,A ; Is the destination one of the
CAILE B,C ; Work registers?
SKIPA ; No skip means it's not A,B, or C
MOVEI B,IDXSAV-1(B) ; So store it in the right TEMP area
MOVEM A,(B) ; Put the results in the destination
DMOVE A,IDXSAV ; Restore AC's
MOVE C,IDXSAV+2 ;
JRST 1(F) ;SKIP RETURN, ROUTINE RETURNS A MESSAGE
;BLOCK POINTER IN THE SPECIFIED REGISTER
; MMAP - Map the Message Index file window
;
; A/ Index block number
MMAP: MOVEM A,IDXNUM ;STORE MESSAGE NUMBER
SKIPL MSGIFJ ;DO WE HAVE A FILE ?
JRST MMAP1 ;YES
CAIG A,777 ;MAYBE WE DO NOT NEED A FILE
JRST [ MOVEI B,777 ;NO, WE DON'T, INITIALIZE LIMITS
MOVEM B,MTOP
SETZM MBOT
RET ] ; and do the work
TOPS10<
MMAP1: HALT > ;NEED STUFF HERE
TOPS20<
CALL OPNFIL ;Open the index file
RET ;An error occurred
HRLZ B,A ;FILE PAGE ZERO
MOVEI A,MSGIDX
ASH A,^D-9 ;WINDOW PAGE NUMBER
HRLI A,.FHSLF
MOVEI C,MSGIDN
HRLI C,(PM%CNT)
PMAP ;FLUSH PAGES
ERJMP [ JWARN (UNEXPECTED PMAP ERROR)
JRST CMDRES] ;GO AWAY
MMAP1: SETOM A ;WILL UNMAP
MOVEI B,MSGIDX
ASH B,^D-9 ;FIRST PAGE NUMBER
HRLI B,.FHSLF
MOVEI C,MSGIDN ;NUMBER OF PAGES
TXO C,PM%CNT
PMAP ;UNMAP OLD PAGES
MOVE A,IDXNUM ;MESSAGE NUMBER
ASH A,^D-9
IMULI A,MSGIDN ;FILE PAGE NUMBER
HRL A,MSGIFJ ;FILE JFN
MOVEI B,MSGIDX ;PROCESS PAGE NUMBER
ASH B,^D-9
HRLI B,.FHSLF ;AND DESIGNATOR
MOVEI C,MSGIDN ;NUMBER OF PAGES
HRLI C,(PM%CNT!PM%WR!PM%RD!PM%PLD) ; Start the I/O now, please
PMAP
ERJMP [ JWARN (UNEXPECTED PMAP ERROR)
JRST CMDRES] ;GO AWAY
MOVE A,IDXNUM ;MESSAGE NUMBER
MOVE B,A
TRZ B,777 ;UPDATE BOUNDARIES
MOVEM B,MBOT
ADDI B,777
MOVEM B,MTOP
RET
>; End TOPS20
; WINDOW SETTING FOR FILE SEARCHING
; ROUTINE MAKES SURE THAT THERE IS AT LEAST 1 PAGE TO THE TOP OF WINDOW
SETSFL::$SAVE <A,B,C,D> ; Save AC's for caller
CAMLE V,FILSIZ ; Is pointer beyond known file length?
IFNSK. ; No skip means it is
PUSH P,LASTRD ; Save last read date
PUSH P,V ; SIZFIL smashes this
MOVE A,MSGJFN ; So get the message file JFN
CALL SIZFIL ; And update the file length
WARN <Internal error - SIZFIL failed at SETSFL>
POP P,V ; Restore pointer
POP P,LASTRD ; and last read date
CAMLE V,FILSIZ ; Check it again
$STOP (BMX, Bad Message Index - Beyond EOF)
ENDIF. ; all set
MOVE A,V
ADDI A,BY2PAG+5 ; Make sure a page or more is around
CAMLE A,FILSIZ ; Are we getting carried away?
MOVE A,FILSIZ ; Let's not cause unnecessary thrashing
CAML V,WBOT ; Are the pointers below bottom of window?
CAMLE A,WTOP ; Or above the top?
CALL REMAP ; Yes, so remap
RET ; Done
TOPS20<
OPNFIL: $SAVE<D> ;Save a working register
OPNFI2: GJINF ;[MDR] Connected dir. in AC2
HRROI A,IDXFIL ;Where to place the file spec
DIRST ;[MDR] Translate conn dir to string
ERJMP JFNSER ;Should not happen
MOVEI C,"M" ;Pick up first part of file name
IDPB C,A ;And include as part of the file spec
MOVEI C,"S"
IDPB C,A
MOVE C,A ;GTAD destroys A
GTAD ;Want 4 numerics to finish file name
MOVNI D,4 ;D is for loop control
NXTDIG: IDIVI A,^D10 ;Peel off another integer
ADDI B,60 ;Make it ASCIZ
IDPB B,C ;Place in the file spec
AOJN D,NXTDIG ;Get the next integer
MOVE B,C ;B is the destination for the SIN%
HRROI A,[ASCIZ /.TMP.1/] ;The string to be copied
SETZ C, ;String ends with a nul{
SIN
ERJMP .+1 ;Should never happen
MOVX A,GJ%NEW!GJ%TMP!GJ%SHT
HRROI B,IDXFIL ;Pointer to the file spec
GTJFN
ERJMP [CAIE A,GJFX27 ;File already exist?
JRST GJFNE ;No, some other error
JRST OPNFI2 ] ;Try a different file name
MOVEM A,MSGIFJ ;SAVE JFN
MOVX B,OF%RD!OF%WR
OPENF ;OPEN IT
ERJMP OPNERR ;Failed to open
RETSKP
JFNSER: JWARN (Cannot obtain file specification for index file)
SKIPA
GJFNE: JWARN(Cannot get index file JFN)
SKIPA
OPNERR: JWARN(Cannot open index file)
RET
>;End of TOPS20
END
; *** Edit 2474 to MSFIL.MAC by PRATT on 18-Nov-85
; Changes for TOPS10 to make MS.MAC smaller
; *** Edit 2475 to MSFIL.MAC by PRATT on 18-Nov-85
; Make FILERR internal
; *** Edit 2480 to MSFIL.MAC by PRATT on 20-Nov-85
; Make sure UNMAPF is internal only for the -20
; *** Edit 2484 to MSFIL.MAC by SANTEE on 21-Nov-85
; Clean up the various edit histories.
; *** Edit 2485 to MSFIL.MAC by MAYO on 21-Nov-85
;
; *** Edit 2486 to MSFIL.MAC by PRATT on 22-Nov-85
; Copyright statements
; *** Edit 2493 to MSFIL.MAC by MAYO on 5-Dec-85
; Make sure the info in MSGSSQ (the SAME array) gets properly translated across
; EXPUNGEs. Prevents users from being able to undelete messages they've already
; expunged.
; *** Edit 2602 to MSFIL.MAC by PRATT on 6-Dec-85
; Catch other case of MAIL window not being mapped after an EXPUNGE
; *** Edit 2614 to MSFIL.MAC by SANTEE on 18-Dec-85
; Keep the number of messages deleted, new, and flagged up-to-date. This makes
; several paths faster and we end up doing alot less work. Also, with windowing
; it is important on the -10 to know if we have any work to do at expunge time.
; Some minor code rearrangements were made in related areas for speed up
; purposes. Finally some comments were added or lined up and paging was
; adjusted in some places.
; *** Edit 2616 to MSFIL.MAC by JROSSELL on 18-Dec-85
; When a message is read or typed; or when SKIM, SUMMARIZE, HEADERS, GET or
; NEXT is given - update the last time the mail file was read. On TOPS20 also
; update the FDB.
; *** Edit 2621 to MSFIL.MAC by SANTEE on 20-Dec-85
; Rearrange Expunge code to take advantage of the now up-to-date NDELET word.
; While we're there rearrange code a little for efficiecy.
; *** Edit 2622 to MSFIL.MAC by PRATT on 23-Dec-85
; Fix "MOVE or DELETE" length invalid error, SET DEF DIR, SET DEF PROT (-10)
; *** Edit 2623 to MSFIL.MAC by PRATT on 23-Dec-85
; Fix lost EXTERN from the last edit
; *** Edit 2624 to MSFIL.MAC by PRATT on 30-Dec-85
; Also add missing edit around PARSEX
; *** Edit 2625 to MSFIL.MAC by PRATT on 2-Jan-86
; Don't propmt for <crlf> if ? typed (in GETOU0)
; *** Edit 2630 to MSFIL.MAC by JROSSELL on 6-Jan-86
; LASTRD is not restored from the stack upon a SIZFIL error in routine GET1.
; This results in the stack becoming corrupt.
; *** Edit 2631 to MSFIL.MAC by PRATT on 7-Jan-86
; More massive changes to Expunge (courtesy of Mark and Ned)
; *** Edit 2634 to MSFIL.MAC by JROSSELL on 10-Jan-86
; Open up a second JFN as READ/WRITE in places where we don't want another
; process writing to the mail file.
; *** Edit 2636 to MSFIL.MAC by APPELLOF on 15-Jan-86
; Finish SET DEFAULT DIRECTORY for TOPS-10
; *** Edit 2639 to MSFIL.MAC by JROSSELL on 22-Jan-86
; When doing a SYSTEM command, do not open the system mail file as READ/WRITE
; *** Edit 2640 to MSFIL.MAC by APPELLOF on 24-Jan-86
; SET/CLEAR the "new mail" bit in mail file RIB on TOPS-10 Bit is lit if there
; are unseen messages. Bit is cleared if there are no unseen messages.
; *** Edit 2641 to MSFIL.MAC by APPELLOF on 27-Jan-86
; Re-apply preceeding edit properly
; *** Edit 2643 to MSFIL.MAC by SANTEE on 27-Jan-86
; Purge extra "Can't determine siz..." message and some general clean up.
; *** Edit 2647 to MSFIL.MAC by SANTEE on 28-Jan-86
; Fix a bug that would blow up a mail file if you recieved mail at just the
; wrong instant. Also, try harder to not leave junk on the end of the mail file
; during expunge.
; *** Edit 2655 to MSFIL.MAC by APPELLOF on 15-Feb-86
; Fix MS-10 to rename or re-write MAIL.TXT to the same path where it was found
; *** Edit 2670 to MSFIL.MAC by SANTEE on 3-Mar-86
; FILSIZ on the -10 didn't reflect the zero offset (one too high). Also, since
; we are no longer reading USERS.TXT we need to lookup MAIL.TXT on DSK:.
; *** Edit 2676 to MSFIL.MAC by JROSSELL on 6-Mar-86
; Prevent PMAP errors when there are more than 512 messages by giving the .TMP
; file a unique name.
; *** Edit 2678 to MSFIL.MAC by SANTEE on 7-Mar-86
; Edit 2670 changed FILSIZ but caused other problems. Remove this part of the
; edit.
; *** Edit 2680 to MSFIL.MAC by SANTEE on 16-Mar-86
; Turn F%F2 off after EXPUNGE. Wierdness happens if you do not. -10 only.
; *** Edit 2681 to MSFIL.MAC by SANTEE on 16-Mar-86
; Rewrite a large portion of PARSEF in an attempt to 1) make the paranoia code
; work (what we do if message byte sizes seem to disagree with what is in the
; file) and 2) to make the whole shebang faster in the process.
; *** Edit 2685 to MSFIL.MAC by SANTEE on 24-Mar-86
; Last edit to PARSEF broke parsing starting in the middle of the file. Set up
; the AC we are going to use rather than another random one.
; *** Edit 2689 to MSFIL.MAC by APPELLOF on 26-Mar-86
; Prevent ERF (Error Reading File) on TOPS-10 if MX is appending when we check
; the size of the mail file. Also cut down on the number of LOOKUPs we do.
; *** Edit 2693 to MSFIL.MAC by APPELLOF on 4-Apr-86
; Fix problem with deleting file after expunge of all messages. Restore LOOKUP
; block length that we blew while reading in a RIB
; *** Edit 2694 to MSFIL.MAC by JROSSELL on 8-Apr-86
; If PARSEF detects that the mail file has changed size, have it assume that
; another reader exists and reparse the mail file. This is for TOPS20 only and
; must be used due to a lack of a complete global ENQ/DEQ mechanism.
; *** Edit 2695 to MSFIL.MAC by APPELLOF on 25-Apr-86
; Fix TOPS-10 code to delete mail file when last message is expunged.
; *** Edit 2701 to MSFIL.MAC by RASPUZZI on 20-May-86
; Make MS create MSxxxx.TMP file in connected directory instead of the
; directory where the MAIL.TXT file resides.
; *** Edit 2706 to MSFIL.MAC by RASPUZZI on 27-May-86
; Teach MS not to use POBOX: when writing files. Instead, find out what STR: is
; being used (saved in MYSTR) and go from there.
; *** Edit 2708 to MSFIL.MAC by PRATT on 30-May-86
; Fix problem with multiple "There are no messages in MAIL.TXT" messages.
; *** Edit 2715 to MSFIL.MAC by RASPUZZI on 6-Jun-86
; Make MS more flexible when encountering "Invalid simultaneous access" on
; MAIL.TXT by trying to open the file 1 time per second for 5 seconds just in
; case MX has the file opened for incoming mail.
; *** Edit 2728 to MSFIL.MAC by RASPUZZI on 19-Jun-86
; Teach MS to use the users definition of LPT: in GETLPT: by lighting the F%F1
; bit (this is never set or cleared in this routine - for shame)