1
0
mirror of https://github.com/PDP-10/stacken.git synced 2026-03-01 01:19:17 +00:00
Files
Lars Brinkhoff 6e18f5ebef Extract files from tape images.
Some tapes could not be extracted.
2021-01-29 10:47:33 +01:00

887 lines
26 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
;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 MSSEQ - Message sequence parsing routines for MS
SEARCH GLXMAC,MSUNV
PROLOG (MSSEQ)
CPYRYT
MSINIT
;Define globals
GLOBS ; Storage
GLOBRS ; Routines
;Global routines defined elsewhere
;MSUTL.MAC
EXTERNAL CMDER1, RFIELD, MOVST0, SSEARC, SETSFL, REMAP, GTBFL
;Global data items defined elsewhere
;MSUTL.MAC
EXTERNAL ATMBUF, MSGFAD, WBOT, WTOP, CMDRES, MSGSSQ, MSGSQE
;Local storage
IMPUR0
MSGSEQ: EXP 0 ; Table of numbers of messages adress
LSTMSG: BLOCK 1 ; Saved last message for typing out seq
SAVEM: BLOCK 1 ; Saved current message number
COMPDT: BLOCK 1 ; Date/time for "since" and "before"
NXTMSG: BLOCK 1 ; Dispatch to fetch next message
PATSTR: BLOCK 40 ; String pattern for from/subj matching
ANDFLG: BLOCK 1 ; Qualifiers being ANDed
PRIORM: BLOCK 1
RECLVL: EXP 0
MSGQLN: BLOCK 1
HEADNR: BLOCK 1
PURE
SUBTTL Message sequence subroutines
; Get sequence
DFSQNW: MOVEI A,DEFNEW ; Default to new (unseen)
JRST GETSEQ
DFSQTH: MOVEI A,DEFCUR ; Default to current message
GETSEQ: PUSH P,A ; Save command block addrs
SETZM LCNT ; Say no matches seen yet
SKIPG MSGJFN ; Have a message file?
CWARN (No current mail file)
NOISE (messages)
MOVEI A,MSGSSQ
SKIPN MSGSEQ
MOVEM A,MSGSEQ ;SET UP ADRESS IF NECESSARY
MOVE L,MSGSEQ
ADD L,[POINT 18,0]
SETOB X,LSTMSG
POP P,A ; Restore command block
CALL RFIELD ; Get command field
MOVE A,CR.COD(A) ; Get code
CAIN A,.CMKEY ; Keyword?
JRST GETSQK ; Yes - done
CAIN A,.CMNUM ; Number?
JRST GETSQN ; Yes - proceed
JRST GETSQT ; Must be token (% or .)
;Keyword seen , handle defaulting and return
GETSQK: HRRZ A,(B) ; Get routine addrs
JRST (A)
;Token - check for % or . and supply number
GETSQT: LDB A,[POINT 7,ATMBUF,6] ; Get token character
CAIN A,"%"
SKIPA B,LASTM ; % = last message number
MOVEI B,(M) ; . = current message number
AOJA B,GETSQN ; Handle as number now
;Number parsed - handle n:m n,m or n alone
GETSQN: JUMPE B,GTSQNE ; Range error
SOJL B,GTSQNE
CAMLE B,LASTM
JRST GTSQNE
JUMPGE X,GTSQN2 ; 2nd in series n:m
IDPB B,L ; Save number in list
CALL CHKL ;CHECK THE RANGE
MOVEI A,GTNBK1 ; Now try for <cr> ! , ! :
GTSQNA: CALL RFIELD
MOVE A,CR.COD(A) ; Get function code parsed
CAIN A,.CMCFM ; EOL?
JRST GTSQNR ; Yes - done
CAIE A,.CMCMA ; Comma?
LDB X,L ; Must be ":" ,setup for 2nd arg
MOVEI A,DEFLST ; Yes - try for <number> ! . ! %
CALL RFIELD
MOVE A,CR.COD(A) ; Get function code
CAIN A,.CMCFM ; EOL?
JRST GTSQNR ; Yes - done
CAIN A,.CMNUM ; Number?
JRST GETSQN ; Yes - handle
CAIN A,.CMKEY ; Keyword?
JRST GETSQK ; Yep, go handle it
JRST GETSQT ; Handle token
;2nd in range seen - fill list
GTSQN2: CAIN X,(B) ; Done with range
JRST GTSQNC ; Look for next field
CAIG X,(B) ; If going forwards,
AOSA X ; increment,
SOS X ; else decrement
IDPB X,L ; Save in table
CALL CHKL ;CHECK THE RANGE
JRST GTSQN2 ; Loop till done
GTSQNC: SETO X, ; Say looking for 1st number of pair
MOVEI A,GTNBK3 ; Try for <cr> ! ,
JRST GTSQNA
;EOL seen , wrapup numbers
GTSQNR: MOVEI B,777777 ; Mark end of list
IDPB B,L
MOVEI A,NXTSEQ ; Next in the sequence
MOVEM A,NXTMSG ; Setup as dispatch
MOVE A,MSGSEQ
ADD A,[POINT 18,0]
EXCH A,L ; Reset L, get old contents
MOVE B,MSGSEQ
ADD B,[POINT 18,0,17]
CAMN A,B ;ANY MESSAGES AT THE LISTAT ALL ?
RET ; No -- leave M alone then
PUSH P,L ; Save these for a bit
PUSH P,M
SETZM LCNT ; Zero msg count
GTSQN3: ILDB M,L ; Check to see all msgs are parsed
CAIN M,777777 ; End of list?
JRST GTSQN4 ; Yes, all done
AOS LCNT ; Count messages in this sequence
GTMBL (M,B) ; Get ptr to message block
MOVX A,M%VALI ; Valid info for this message?
TDNN A,MSGBTS(B) ; ..
CALL PRSMS0 ; No, get some then
JRST GTSQN3 ; Check all msgs in sequence
GTSQN4: POP P,M
POP P,L ; Finish up
RET ; Return
GTSQNE: CMERR (Invalid message number)
JRST CMDER1
DEFCUR: FLDDB1 (.CMNUM,CM%SDH,^D10,<-1,,SEQHLP>,<current>,DEFDEF)
DEFNEW: FLDDB1 (.CMNUM,CM%SDH,^D10,<-1,,SEQHLP>,<new>,DEFDEF)
DEFALL: FLDDB1 (.CMNUM,CM%SDH,^D10,<-1,,SEQHLP>,<all>,DEFDEF)
DEFLST: FLDDB1 (.CMNUM,CM%SDH,^D10,<-1,,SEQHLP>,<last>,DEFDEF)
DEFDEF: FLDDB1 (.CMTOK,,<POINT 7,[ASCII "%"]>,,,TKNDOT)
TKNDOT: FLDDB1 (.CMTOK,,<POINT 7,[ASCII "."]>,,,[FLDDB1 (.CMKEY,,SQCMTB)])
GTNBK1: FLDDB1 (.CMCFM,,,,,[FLDDB1 (.CMCMA,,,,,[FLDDB1 (.CMTOK,,<POINT 7,[ASCII ":"]>)])])
GTNBK3: FLDDB1 (.CMCFM,,,,,[FLDDB1 (.CMCMA)])
SEQHLP: ASCIZ \message sequence, one of the following:
message number
or list of numbers (4,14,11,...)
or range of numbers (11:37)\
SQCMTB: NSQCMS,,NSQCMS
CMD1 (A,ENTALL,CM%INV!CM%ABR)
ENTALL: CMD1 (All,STQALL)
CMD1 (Answered,STQANS)
CMD1 (Before,STQTMB)
CMD1 (Current,STQCUR)
CMD1 (Deleted,STQDEL)
CMD1 (F,ENTFRM,CM%INV!CM%ABR)
CMD1 (First,STQFRS)
CMD1 (Flagged,STQFLG)
ENTFRM: CMD1 (From,STQFRM)
CMD1 (Inverse,STQREV)
CMD1 (Keyword,STQKWD)
CMD1 (L,ENTLST,CM%INV!CM%ABR)
CMD1 (Larger,STQLRG)
ENTLST: CMD1 (Last,STQLST)
CMD1 (N,ENTNEW,CM%INV!CM%ABR)
ENTNEW: CMD1 (New,STQNEW)
CMD1 (Next,STQNXT)
CMD1 (Old,STQOLD)
CMD1 (Related-to,STQREL)
CMD1 (Same,STQSAM)
CMD1 (Since,STQTMS)
CMD1 (Smaller,STQSML)
CMD1 (Sorted,STQSOR)
CMD1 (Subject,STQSBJ)
CMD1 (To,STQTO)
CMD1 (Unanswered,STQUNA)
CMD1 (Undeleted,STQUND)
CMD1 (Unflagged,STQUNF)
NSQCMS==.-SQCMTB-1
STQSRC: STQSRN,,STQSRN
CMD1 (Date-time,SQSRDT)
STQSRN==.-STQSRC-1
STQSAM: NOISE (as last sequence)
CONFRM
MOVE C,MSGSEQ
HRLI C,(POINT 18)
MOVE L,C ;RETURN THIS IN L
SETZ D,
STQSA0: ILDB A,C ; Get msg number
CAIE A,777777 ; Check for terminator
AOJA D,STQSA0
STQSA1: MOVEM D,LCNT ; Save count
CAIG D,0 ; If none...
WARN <No previous sequence exists> ;Complain here
RET
;Larger (than) n (characters)
STQLRG: CALL STQLR0 ; Parse character count
STQLR1: GTMBL (M,A) ; Get ptr to message block
CAMGE B,MSGBON(A) ; Is this one big enough?
IDPB M,L ; Yes, add to sequence
CALL CHKL ;CHECK THE RANGE
CAME M,LASTM ; Loop through all messages
AOJA M,STQLR1 ; ..
JRST GTSQNR ; Finished
;Smaller (than) n (characters)
STQSML: CALL STQLR0 ; Parse character count
STQSM1: GTMBL (M,A) ; Get ptr to message block
CAMLE B,MSGBON(A) ; Match?
IDPB M,L ; Yes, stuff into sequence
CALL CHKL ;CHECK THE RANGE
CAME M,LASTM ; Loop over all msgs
AOJA M,STQSM1 ; ..
JRST GTSQNR ; Done
STQLR0: NOISE (than)
MOVEI A,[FLDDB. (.CMNUM,CM%SDH,^D10,<character count>)]
CALL RFIELD
SETZ M, ; Init message pointer
PUSH P,B ; Save size limit
NOISE (characters)
CONFRM
POP P,B ; Restore size limit
RET
STQSOR: NOISE (by)
MOVEI A,[FLDDB. (.CMKEY,,STQSRC,,<Date-time>)]
CALL RFIELD
HRRZ A,(B) ; Dispatch to sort routine
CALLRET (A)
;Sort by date/time
SQSRDT: TRVAR <LOW,LOWM> ; Low date/time, and its M
CONFRM
SETZ M,
SQSRD0: GTMBL (M,B) ; Get ptr to message block
MOVX A,M%TEMP ; Temporary marker bit
ANDCAM A,MSGBTS(B) ; Clear markers
MOVX A,M%VALI ; Parsed this one yet?
TDNN A,MSGBTS(B) ; ..
CALL PRSMS0 ; No, insure it has a date/time
CAME M,LASTM ; for all messagges
AOJA M,SQSRD0
SETOM LOWM ; Flag nothing found yet
MOVE A,[377777,,777777] ; Get largest integer
MOVEM A,LOW ; Init floor counter
SETZ M,
SQSRD1: GTMBL (M,B) ; Get ptr to message block
MOVX A,M%TEMP ; Skip this message
TDNE A,MSGBTS(B) ; if already done
JRST SQSRD2 ; ..
MOVE A,MSGDAT(B) ; Get this msgs date
CAMGE A,LOW ; Is this lowest yet?
JRST [ MOVEM M,LOWM ; Yes, remember it
MOVEM A,LOW ; and its date/time
JRST .+1]
SQSRD2: CAME M,LASTM ; Check all msgs
AOJA M,SQSRD1 ; ..
SKIPGE M,LOWM ; Did we find one?
JRST GTSQNR ; No, all done then - tie off sequence
IDPB M,L ; Yes, stuff into sequence
CALL CHKL ;CHECK THE RANGE
GTMBL (M,B) ; Get ptr to message block
MOVX A,M%TEMP ; Mark this one as gotten
IORM A,MSGBTS(B) ; ..
SETZ M, ; Begin scan again
SETOM LOWM ; Flag nothing found this scan yet
MOVE A,[377777,,777777] ; Init ceiling again
MOVEM A,LOW ; ..
JRST SQSRD1 ; ..
STQALL: SKIPA A,[NXTALL]
STQDEL: MOVEI A,NXTDEL
STQDL0: MOVEM A,NXTMSG
CONFRM ; Get confirmation
MOVEM M,SAVEM ; Save current in case none in list
STQDL2: SETO M,
STQDL1: CALL @NXTMSG ; Get next in sequence
JRST GTSQNR ; No more, finish up
IDPB M,L ; Save this one in list
CALL CHKL ;CHECK THE RANGE
JRST STQDL1 ; Go for more
STQFLG: SKIPA A,[NXTFLG]
STQUND: MOVEI A,NXTUND
JRST STQDL0
STQNEW: SKIPA A,[NXTNEW]
STQOLD: MOVEI A,NXTOLD
JRST STQDL0
;Related-to (messages)
STQREL: CALL DFSQTH ; Get sequence, default to current
PUSH P,[-1] ; Put a marker on the stack
STQRL0: CALL NXTSEQ ; Get next message from sequence of originals
JRST STQRL1 ; None left
PUSH P,M ; Push this message number
JRST STQRL0 ; Push all message numbers from original seq.
STQRL1: MOVE L,MSGSEQ
ADD L,[POINT 18,0] ;RESET SEQUENCE POINTER
STQRL2: POP P,M ; Get a message from the original sequence
CAMN M,[-1] ; Hit the marker (end of stack) yet?
JRST GTSQNR ; Yes, done then, tie off sequence and return
MOVEM M,HEADNR ;SAVE HEAD NUMBER
CALL RELSEQ ; No, add msgs related to this one to sequence
JFCL ; Don't care if none found
JRST STQRL2 ; Repeat for all msgs in original sequence
STQLST: CALL STQLSS ; Get number of messages to put into list
JRST GTSQNE ; Range error
MOVE C,LASTM ; Number of last message
JUMPL X,STQLS2 ; If no previous no. with colon, this is easy
MOVE B,C ; There was one, set up to count from there
JRST GTSQN2 ; Go count from number to end
STQLS2: IDPB C,L ; Stuff message numbers
CALL CHKL ;CHECK THE RANGE
SUBI C,1 ; Next message from end
SOJG A,STQLS2 ; Do for all in list
CONFRM
JRST GTSQNR ; Done with list
STQNXT: CALL STQLSS
JRST GTSQNE
JUMPGE X,RANNXT
MOVE C,M ;START FROM WHERE WE WERE
CAML C,LASTM ;MAKE SURE NOT AT END
JRST GTSQNE ;GO COMPLAIN
STQNX2: ADDI C,1 ;+1
IDPB C,L
CALL CHKL
CAMGE C,LASTM ;AT END? QUIT NICELY
SOJG A,STQNX2 ;CAN STILL GO ON
JRST GTSQNC ;GO PARSE MORE
RANNXT: MOVE B,X ;Start from beginning of range
ADD B,A ;up by arg to NEXT
CAMLE B,LASTM
MOVE B,LASTM ;MAX fo LASTM
JRST GTSQN2 ;GO FILL RANGE
STQFRS: CALL STQLSS ; Similarly, first n messages
JRST GTSQNE ; ..
SETZ C, ; ..
STQFR2: IDPB C,L ; ..
CALL CHKL ;CHECK THE RANGE
ADDI C,1 ; ..
SOJG A,STQFR2 ; ..
CONFRM
JRST GTSQNR ; ..
STQLSS: MOVEI A,[FLDDB. (.CMNUM,,^D10,,<1>)]
CALL RFIELD
PUSH P,B ; NOISEs clobber this
CAIE B,1 ; Singular?
JRST STQLS0 ; No, use plural
NOISE (message)
JRST STQLS1
STQLS0: NOISE (messages)
STQLS1: POP P,A ; Restore number typed
JUMPLE A,R ; Range check
SUBI A,1 ; LASTM is counted from zero
CAMLE A,LASTM ; ..
RET ; ..
ADDI A,1 ; recorrect A
RETSKP ; Good return
STQCUR: MOVEI B,(M) ; Default to current
IDPB B,L ; Save on list
CALL CHKL ;CHECK THE RANGE
CONFRM ; Grntee EOL
JRST GTSQNR ; Done with list
STQUNF: SKIPA A,[NXTUNF]
STQREV: MOVEI A,NXTREV ; Reverse order
JRST STQDL0
STQANS: SKIPA A,[NXTANS] ; Answered
STQUNA: MOVEI A,NXTUNA ; Unanswered
JRST STQDL0
STQFRM: MOVEI X,NXTFRM ; Match "from" string
MOVEI A,[FLDDB. (.CMCFM,CM%SDH,,,,[FLDDB. (.CMQST,,,<string to find in "From" field,
>,,[FLDDB. (.CMTXT)])])]
JRST STQSB0 ; Common routine to get pattern
STQTO: MOVEI X,NXTTO ; Find "to" string
MOVEI A,[FLDDB. (.CMCFM,CM%SDH,,,,[FLDDB. (.CMQST,,,<string to find in "To" field,
>,,[FLDDB. (.CMTXT)])])]
JRST STQSB0
STQKWD: MOVEI X,NXTKWD ; Match keyword in header or text
MOVEI A,[FLDDB. (.CMCFM,CM%SDH,,,,[FLDDB. (.CMQST,,,<string to find anywhere in message,
>,,[FLDDB. (.CMTXT)])])]
JRST STQSB0
STQSBJ: MOVEI X,NXTSBJ ; Match subject string
MOVEI A,[FLDDB. (.CMCFM,CM%SDH,,,,[FLDDB. (.CMQST,,,<string to find in "Subject" field,
>,,[FLDDB. (.CMTXT)])])]
STQSB0: PUSH P,A ; Save arg
NOISE (string)
POP P,A
CALL RFIELD ; Read subject line or crlf
MOVE A,CR.COD(A) ; Get code
CAIN A,.CMCFM ; Just CR?
JRST [ CMERR <No string given.> ; Yes - error
JRST CMDER1]
CAIN A,.CMQST ; Quoted string?
SETOM ANDFLG ; Yes, flag that we might "and" qualifiers
MOVEI B,ATMBUF ; Copy string to pattern buffer
MOVEI A,PATSTR
HRLI A,(POINT 7,)
CALL MOVST0
MOVE A,X ; Routine addrs
JRST STQDL0
;Find substring in From, To, or Subject field
NXTKWD: SKIPA C,[CALL KWDSTR] ; Routine to match keyword in message
NXTTO: MOVE C,[CALL TOSTR] ; Routine to match To string
JRST NXTAL0 ; Join common loop
NXTSBJ: SKIPA C,[CALL SBJSTR] ; Routine to match Subject string
NXTFRM: MOVE C,[CALL FRMSTR] ; Routine to match From string
JRST NXTAL0 ; Use common loop
;Test routines to check for a string match in a message. These are all
; called with D/ pointer to message block (MSGIDX(M))
FRMSTR: $SAVE <A,C> ; Save these regs
MOVEI T,PATSTR ; String to match
MOVE V,MSGFRM(D) ; From field for this message
MOVE W,MSGFRN(D)
CALL SETSFL ;MAKE SURE 1 PAGE IS IN THE WINDOW
MOVE A,MSGFAD
IMULI A,5
SUB V,WBOT
ADD V,A ;MAKE NORMAL CHAR POINTER
CALL SSEARC ; Look for string
RETSKP ; Not found - try next
RET ; Found - use this
SBJSTR: $SAVE <A,C> ; Save these regs
MOVEI T,PATSTR ; String to match
MOVE V,MSGSUB(D) ; Subject field for this message
MOVE W,MSGSUN(D)
CALL SETSFL ;MAKE SURE 1 PAGE IS IN THE WINDOW
MOVE A,MSGFAD
IMULI A,5
SUB V,WBOT
ADD V,A ;MAKE NORMAL CHAR POINTER
CALL SSEARC ; Look for string
RETSKP ; Not found - try next
RET ; Found - use this
TOSTR: $SAVE <A,C> ; Save these regs
PUSH P,D
MOVEI T,PATSTR ; String to match
MOVE V,MSGTO(D) ; To field for this message
MOVE W,MSGTOK(D) ; Use entire To field
CALL SETSFL ;MAKE SURE 1 PAGE IS IN THE WINDOW
MOVE A,MSGFAD
IMULI A,5
SUB V,WBOT
ADD V,A ;MAKE NORMAL CHAR POINTER
CALL SSEARC
SKIPA ; Not found, try CC field
JRST [ POP P,D ; Found... but don't jump into garbage!
RET ]
POP P,D ; SSearch trashes many things...
SKIPN V,MSGCC(D) ; Is there any CC field to search?
RETSKP ; Apparently not...
MOVE W,MSGCCN(D)
MOVEI T,PATSTR ; SSearch trashes this too!
MOVE A,MSGFAD
IMULI A,5
SUB V,WBOT
ADD V,A ; Make char pointer
CALL SSEARC
RETSKP ; Not in CC either
RET ; Got it!
KWDSTR: $SAVE <A,C> ; Save these regs
STKVAR <COUNT>
MOVE V,MSGBOD(D) ; Point to entire message
MOVE W,MSGBON(D) ; ..
CALL SETSFL ;make sure we are all right
KWDS1: MOVEI T,PATSTR ; String to match
MOVNM W,COUNT ;COMMON COUNT (NEGATIVE)
ADD W,V ;POINTER TO THE END OF THE FIELD
CAMLE W,WTOP ;FIT ?
MOVE W,WTOP ;NO
SUB W,V ;ACTUAL LENGHT
ADDM W,COUNT ;UPDATE COUNT
MOVE A,MSGFAD
IMULI A,5
SUB V,WBOT
ADD V,A
CALL SSEARC ; Check for this string
SKIPA
RET ; Found
SKIPN W,COUNT ; Not found
RETSKP ;AND NOTHING TO SEARCH FOR
MOVN W,W ;NEW COUNT
MOVE V,WTOP ;NOW BEGIN FROM THE TOP
SUBI V,40 ;A LITTLE BACK UP
CALL REMAP ;REMAP
JRST KWDS1 ;AND LOOK MORE
; Get date-time arg for "before" and "since" keywords
STQTMB: MOVEI X,NXTTMB ; Rountine addrs
MOVEI A,DEFTMB ; Date/time parse
JRST STQTIM
STQTMS: MOVEI X,NXTTMS ; Routine addrs
MOVEI A,DEFTMS ; Date/time parse
STQTIM: PUSH P,A ; Save arg
NOISE (Date and Time)
POP P,A ; Restore arg
CALL RFIELD
MOVEM B,COMPDT ; Save it for compare
MOVE A,X ; Copy routine to a
JRST STQDL0 ; Common exit
DEFTMB: FLDDB1 (.CMTAD,CM%SDH,<CM%IDA!CM%ITM!TOPS10<CM%PST>>,<-1,,TMBTXT>,,DEFTIM)
DEFTMS: FLDDB1 (.CMTAD,CM%SDH,<CM%IDA!CM%ITM!TOPS10<CM%PST>>,<-1,,TMSTXT>,,DEFTIM)
DEFTIM: FLDDB1 (.CMTAD,CM%SDH,<CM%IDA!TOPS10<CM%PST>>,,,[FLDDB1 (.CMTAD,CM%SDH,<CM%ITM!TOPS10<CM%PST>>)])
TMBTXT: ASCIZ \Date and Time:
Only messages with date-times prior to the specified
date and time will be used.\
TMSTXT: ASCIZ \Date and Time:
Only messages with date-times greater than or equal to the
specified date and time will be used.\
; Compare date/time
NXTTMB: SKIPA C,[CAMLE B,MSGDAT(D)]
NXTTMS: MOVE C,[CAMG B,MSGDAT(D)]
MOVE B,COMPDT ; Date/time to compare against
JRST NXTAL0 ; Use common rountine
; Print out sequence
PRTSEQ: SKIPGE A,LSTMSG ; Any last message?
JRST PRTSQ3 ; No, install this one then
CAIE M,-1(A) ; Yes, is this next or previous?
CAIN M,1(A) ; ..
JRST PRTSQ2 ; Yes, keep accumulating
CALL PRTSQS ; Print what is there now otherwise
PRTSQ1: HRLM M,LSTMSG ; And set ourselves up as start
PRTSQ2: HRRM M,LSTMSG ; Set ourselves up as next link in chain
RET
PRTSQ3: TXZ F,F%CMA ; Reset comma flag
JRST PRTSQ1
PRTSQS: SKIPGE LSTMSG ; Any messages selected at all?
JRST [ WARN <No messages match this specification>
RET]
TXOE F,F%CMA ; Maybe a comma first
$TEXT (KBFTOR,<,^A>)
HLRZ A,LSTMSG ; Start of sequence
ADDI A,1 ; Make real message number
$TEXT (KBFTOR,< ^D/A/^A>)
HRRZ B,LSTMSG ; End of sequence
CAIN A,1(B) ; Same (ie., sequence of one)?
JRST PRTSQ0 ; Yes, quit
ADDI B,1 ; Actual is 1 more than LSTMSG
$TEXT (KBFTOR,<:^D/B/^A>)
PRTSQ0: $CALL K%FLSH ; This can be slow, so say something
RET ; Return
; Get next messages
NXTSEQ: PUSH P,L ; Save msg pointer
ILDB A,L ; Get next byte
CAIE A,777777 ; End?
JRST NXTSQ0 ; No, return msg number in M
POP P,L ; Yes, restore L to prevent running past fence
RET ; Yes,single return
NXTSQ0: POP P,M ; Adjust stack
MOVEI M,(A) ; No, this is next message
RETSKP ; Skip return
NXTSQ1: MOVEI M,(A) ; No, this is next message
RETSKP ; Skip return
;Routines to select messages based on message flag bits.
; These routines need not parse the messages (unless a match is found,
; in which case GTSQNR will parse them.)
NXTANS: SKIPA B,[M%RPLY] ; Answered
NXTOLD: MOVX B,M%SEEN ; Old := seen bit set
JRST NXTDL0
NXTFLG: SKIPA B,[M%ATTN] ; Flagged
NXTDEL: MOVX B,M%DELE ; Deleted
NXTDL0: MOVE C,[TDNE B,MSGBTS(D)] ; Bit must be set
JRST NXTAL4
NXTUNA: SKIPA B,[M%RPLY] ; Unanswered
NXTUNF: MOVX B,M%ATTN ; Unflagged
JRST NXTUD0
NXTNEW: SKIPA B,[M%SEEN] ; New := seen bit clear
NXTUND: MOVX B,M%DELE ; Undeleted
NXTUD0: MOVE C,[TDNN B,MSGBTS(D)] ; Bit must be clear
NXTAL4: MOVEI A,1(M) ; Start here
NXTAL5: CAMLE A,LASTM ; Done?
JRST NXTEND ; Yes, see if any found
GTMBL (A,D) ; Get ptr to message block
XCT C ; Test this message
JRST NXTSQ1 ; Matches -- add to list
AOJA A,NXTAL5 ; No match, check next
;If selecting messages based on contents, must insure that the
; message is parsed before calling selection routine
NXTALL: MOVSI C,(<JFCL>) ; All := pass all thru
NXTAL0: MOVEI A,1(M) ; Start here
NXTAL1: CAMLE A,LASTM ; Done?
JRST NXTEND ; Check if any done
PUSH P,E
GTMBL (A,D) ; Get ptr to message block
MOVX E,M%VALI ; Valid info for this msg?
TDNN E,MSGBTS(D) ; If not, must parse it before testing it
JRST [ EXCH A,M ; Msg to parse is c(A)
PUSH P,C ; Save test instruction
CALL PRSMSG ; Go parse it
POP P,C
EXCH A,M ; Restore ACs
JRST .+1] ; Go test it now
POP P,E
XCT C ; Test it out
JRST NXTSQ1 ; Matches
AOJA A,NXTAL1 ; No good, try next one
NXTEND: JUMPGE M,R ; Ok if not -1
HRRZ M,SAVEM ; else restore prior current msg
RET
NXTREV: JUMPGE M,NXTRV1 ; First time here?
HRRZ A,LASTM ; Yes - start at end
JRST NXTSQ1
NXTRV1: MOVEI A,(M) ; Try next
SOJGE A,NXTSQ1 ; Keep going till all done
RET
;Form message sequence of messages related to current one
;Return +1: no related messages found
; +2: related messages found and sequence stored
RELSEQ: TRVAR <MIDX,THISL,THISM>
MOVEM L,THISL ; Save current sequence pointer
MOVEM M,THISM ; Save current M
GTMBL (M,B) ; Get ptr to message block
MOVEM B,MIDX ; Save in safe place
MOVX A,M%VALI ; Insure we've got valid information
TDNN A,MSGBTS(B) ; for this message
CALL PRSMS0 ; ..
MOVE B,MIDX ; Get index back
SKIPN V,MSGREF(B) ; Any 'Reference:' field?
JRST RELSQ0 ; No, go check for replies to this then
MOVE W,MSGRFN(B) ; Yes, get its length
CALL FEQMID ; Find equal message-ID's
RELSQ0: MOVE B,MIDX ; Restore Msg index, clobbered by FEQMID
SKIPN V,MSGMID(B) ; Does this message have a message-ID?
JRST RELSQX ; Doesn't have one, all done
MOVE W,MSGMIN(B) ; Yes, get its length
MOVE M,THISM ; Restore M for FEQREF
CALL FEQREF ; Find equal reference fields
RELSQX: MOVE M,THISM ; Restore M
CAMN L,THISL ; Any messages added to sequence?
RET ; No, failure return
RETSKP
;FEQMID - Find message-ID's with equal contents to string
;FEQREF - Find references with equal contents to string
;Recurses up-level to RELSEQ to find messages related to messages related to...
;Call:
; V/ character address of test string
; W/ length of test string
;Return +1: always, messages added to sequence via IDPB M,L
FEQMID: MOVEI A,MSGMID ; Load address of field we're searching
MOVEI B,MSGMIN ; and its length
JRST FEQ0 ; Go join common code
FEQREF: MOVEI A,MSGREF ; Same for reference field
MOVEI B,MSGRFN ; ..
FEQ0: TRVAR <VW2,<MN2,2>,BADR,BLEN,MM>
MOVEM W,VW2 ; Save pointer and length to test string
DMOVEM A,MN2 ; and pointers to ptr and length of object
MOVEM M,MM ;STORE MESSAGE NUMBER
;NOW MOVE TEST STRING
MOVE A,W ;SIZE OF TEST STRING
ADDI A,5
IDIVI A,5 ;IN WORDS
MOVEM A,BLEN
$CALL M%GMEM ;GET MEMORY
JUMPF [WARN (SHORTAGE OF MEMORY IN FEQMID)
RET]
MOVEM B,BADR ;STORE THE ADRESS
ADD B,[POINT 7,0]
EQQ1: CALL GTBFL
AOS V
IDPB A,B ;MOVE BYTE
SOJG W,EQQ1 ;LOOP UNTIL DONE
SETZ M, ; Scan all messages
EQFSQ0: CAME M,MM ;DON'T CHECK ITSELF
CALL CHKPRS ; Check for presence of this msg already
JRST EQFSQ2 ; Already present, don't recurse infinitely
CAMN M,HEADNR ;DON'T CHECK ROOT NUMBER
JRST EQFSQ2
MOVX A,M%VALI ; Have valid data for this message yet?
GTMBL (M,B) ; Get ptr to message block
TDNN A,MSGBTS(B) ; ..
CALL PRSMS0 ; No, go parse it then
DMOVE A,MN2 ; Get ptr and length for MSGMID/MSGREF
PUSH P,A
GTMBL (M,A) ; Get ptr to message block
ADD A,(P) ; Index to current message
ADJSP P,-1
SKIPN V,(A) ; Get appropriate character pointer
JRST EQFSQ2 ; Doesn't have one, so skip it
PUSH P,B
GTMBL (M,B) ; Get ptr to message block
ADD B,(P) ; Index to current message
ADJSP P,-1
SKIPN D,(B) ; Get length of object string
JRST EQFSQ2 ; Zero length, skip this
MOVE W,VW2 ; Get length of test string
CAMLE W,D ; Use MIN of object length and test length
MOVE W,D ; ..
MOVE D,BADR
ADD D,[POINT 7,0] ;CHAR POINTER
EQFSQ1: CALL GTBFL ; Get character of header contents
AOS V
ILDB B,D ; Get character of test string
CAME A,B ; Matching?
JRST EQFSQ2 ; No, skip this message then
SOJG W,EQFSQ1 ; Yes, do for all chars in test string
IDPB M,L ; This message matches, add to sequence
CALL CHKL ;CHECK THE RANGE
CALL RELSEQ ; Now add msgs related to this one, recursively
JFCL ; Don't care if none found here
EQFSQ2: CAME M,LASTM ; At last message?
AOJA M,EQFSQ0 ; Not yet, keep going
MOVE A,BLEN
MOVE B,BADR
$CALL M%RMEM
RET ; Yes, return
;CHECK TO SEE IF THERE IS MEMORY TO STORE 1 ELEMENT
CHKL: PUSH P,L
MOVEI L,1
ADJBP L,(P) ;EVALUATING I
TLZ L,777777 ;ADRESS
CAIN L,MSGSQE ;LAST WORD ?
JRST NOMEM ;YES, ALARM
POP P,L
RET ;RETURN
NOMEM: MOVE A,MSGSEQ
CAIE A,MSGSSQ ;ARE WE AT THE VERY BEGINNING ?
JRST [ PUSH P,F ;NO
JSP F,RESMSQ ;RESTORE CONTEXT
POP P,F
JRST .+1]
CMERR <ADRESS SPACE TO STORE SEQUENCE EXHAUSTED>
JRST CMDER1 ;AND GO TO THE START
;Check to see if a message, M, is already in the list
;Return +1: already present
; +2: not there yet
CHKPRS: MOVE D,MSGSEQ
ADD D,[POINT 18,0]
CHKPR0: CAMN D,L ; Reached end of list yet?
JRST RSKP ; Yes, give good return
ILDB A,D ; No, get next message number
CAME A,M ; Is this message it?
JRST CHKPR0 ; No, keep looking
RET ; Yes, give nonskip return
;SEQUENCE SAVE/RESTORE ROUTINES
;SAVE MESSAGE SEQUENCE
SAVMSQ: TRVAR <<SAVLM,2>,SAVPRI,SVLCNT>
DMOVEM L,SAVLM ; Save current read mode context L,M
MOVE A,PRIORM ; ..
MOVEM A,SAVPRI ; ..
MOVE A,LCNT ; Save count of msgs in this sequence
MOVEM A,SVLCNT ; ..
JUMPE A,RRR ; If no msgs to save, don't!
ADDI A,2 ;NO,COMPUTE BLOCK LENGHT
ASH A,-1 ;IN WORDS
MOVE B,MSGSEQ ;SEQUENCE START ADRESS
ADD A,B ;NEXT SEQUENCE START ADRESS
CAIL A,MSGSQE ;NO MEMORY ?
JRST NOMEM ;NO ANYMORE
MOVEM A,MSGSEQ ;SAVE ITS ADRESS
RRR: JRST (F) ;RETURN
;RESTORE MESSAGE SEQUENCE
RESMSQ: MOVE A,SVLCNT ; Get count of saved messages
MOVEM A,LCNT ; Restore
JUMPE A,RES1 ; If none, this is easy
ADDI A,2 ;NO,COMPUTE BLOCK LENGHT
ASH A,-1 ;IN WORDS
MOVE B,MSGSEQ ;GET ITS ADRESS
SUB B,A ; Compute BLT fence
MOVEM B,MSGSEQ ; RESTORE message sequence
RES1: MOVE A,SAVPRI ;; ..
MOVEM A,PRIORM ;; ..
DMOVE L,SAVLM ;; ..
JRST (F) ;DONE
END
; Edit 2452 to MSSEQ.MAC by MAYO on 18-Oct-85
; "verb SAME" shouldn't always claim %No previous sequence exists
; *** Edit 2486 to MSSEQ.MAC by PRATT on 22-Nov-85
; Copyright statements
; *** Edit 2494 to MSSEQ.MAC by MAYO on 5-Dec-85
; Add NEXT n for commands like READ, SUMMAR, etc.
; *** Edit 2601 to MSSEQ.MAC by MAYO on 5-Dec-85
; Allow number:NEXT n to do useful things.