mirror of
https://github.com/PDP-10/stacken.git
synced 2026-03-01 01:19:17 +00:00
887 lines
26 KiB
Plaintext
887 lines
26 KiB
Plaintext
;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.
|