(DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10)

(FILECREATED "11-May-2023 21:39:24" {DSK}<cygdrive>c>Users>Larry>home>il>MEDLEY>SOURCES>LEAF.;2 741527Q

      :EDIT-BY "lmm"

      :CHANGES-TO (VARS LEAFCOMPILETIMECOMS)

      :PREVIOUS-DATE "19-Jan-93 10:41:31" {DSK}<cygdrive>c>Users>Larry>home>il>MEDLEY>SOURCES>LEAF.;1
)


(PRETTYCOMPRINT LEAFCOMS)

(RPAQQ LEAFCOMS
       (

(* ;;; "Support for the Leaf random-access filing protocol")

        (E (RESETSAVE (RADIX 8)))
        (COMS 
              (* ;; "SEQUIN protocol")

              (DECLARE%: EVAL@COMPILE DONTCOPY (COMS * SEQUINCOMS)
                     (FILES (LOADCOMP)
                            TCPHTE))
              (INITRECORDS SEQUIN)
              (SYSRECORDS SEQUIN)
              (FNS CLOSESEQUIN INITSEQUIN GETSEQUIN PUTSEQUIN)
              (FNS \SEQUIN.CONTROL \SEQUIN.PUT \SEQUIN.PROCESS \SEQUIN.CLOSE \SEQUIN.FLUSH.CONNECTION
                   \SEQUIN.CLEANUP \SEQUIN.FLUSH.RETRANSMIT \SEQUIN.COMPARE \SEQUIN.HANDLE.INPUT 
                   \SEQUIN.OUT.OF.THE.BLUE \SEQUIN.HANDLE.ACK \SEQUIN.RETRANSMIT 
                   \SEQUIN.RETRANSMITNEXT))
        (COMS 
              (* ;; "LEAF device operations")

              (FNS \LEAF.CLOSEFILE \LEAF.DELETEFILE \LEAF.DEVICEP \LEAF.RECONNECT 
                   \LEAF.DIRECTORYNAMEP \LEAF.GENERATEFILES \LEAF.GETFILE \PARSE.REMOTE.FILENAME 
                   \LEAF.STRIP.QUOTES \LEAF.GETFILEDATES \LEAF.GETFILEINFO \LEAF.GETFILEINFO.OPEN 
                   \LEAF.GETFILENAME \LEAF.OPENFILE \LEAF.READFILENAME \LEAF.ADD.QUOTES 
                   \LEAF.READFILEPROP \LEAF.READPAGES \LEAF.REQUESTPAGE \LEAF.LOOKUPCACHE 
                   CLEAR.LEAF.CACHE LEAF.ASSURE.FINISHED \LEAF.FORCEOUTPUT \LEAF.FLUSH.CACHE 
                   \LEAF.RENAMEFILE \LEAF.REOPENFILE \LEAF.CREATIONDATE \LEAF.SETCREATIONDATE 
                   \LEAF.SETFILEINFO \LEAF.SETFILETYPE \LEAF.SETVALIDATION \LEAF.TRUNCATEFILE 
                   \LEAF.WRITEPAGES))
        (COMS 
              (* ;; "Main routing point for LEAF pups")

              (FNS \SENDLEAF))
        (COMS 
              (* ;; "Managing LEAF connections")

              (FNS \OPENLEAFCONNECTION \LEAF.BREAKCONNECTION \CLOSELEAFCONNECTION \LEAF.EVENTFN)
                                                             (* ; 
                                                             "This generic fn ought to be on FILEIO")
              (FNS BREAKCONNECTION))
        (COMS 
              (* ;; "Functions called when various SEQUIN events occur")

              (FNS \LEAF.ACKED \LEAF.FIX.BROKEN.SEQUIN \LEAF.REPAIR.BROKEN.PUP 
                   \LEAF.USE.NEW.CONNECTION \LEAF.RESENDPUPS \LEAF.HANDLE.INPUT 
                   \LEAF.OPENERRORHANDLER \LEAF.TIMEDIN \LEAF.TIMEDOUT \LEAF.NOT.RESPONDING 
                   \LEAF.TIMEDOUT.EXCESSIVE \LEAF.ABORT.FROMMENU \LEAF.STREAM.IN.QUEUE \LEAF.IDLE 
                   \LEAF.MAYBE.FLUSH.CACHE \LEAF.WHENCLOSED \LEAF.IDLE?))
        (ADDVARS (NETWORKOSTYPES))
        (COMS 
              (* ;; "Miscellaneous and error handling")

              (FNS \ADDLEAFSTRING \FIXPASSWORD \GETLEAFSTRING \IFSERRORSTRING \LEAF.ERROR 
                   \LEAF.DIRECTORYNAMEONLY GETHOSTINFO GETOSTYPE EXPANDING-PAGEFULLFN)
              (VARS (DEFAULT.OSTYPE 'IFS))
              (GLOBALVARS DEFAULT.OSTYPE))
        (COMS 
              (* ;; "LookUpFile stuff")

              (FNS \IFS.LOOKUPFILE)
              (DECLARE%: EVAL@COMPILE DONTCOPY (COMS * LOOKUPFILECOMS)))
        [COMS (FNS \LEAFINIT)
              (DECLARE%: DONTEVAL@LOAD (P (\LEAFINIT]
        (COMS (FNS PRINTLEAF)
              (ALISTS (PUPPRINTMACROS 176)))
        (INITVARS (LEAFDEBUGFLG)
               (LEAFABORTREGION '(417 616 399 192))
               (\MAXLEAFTRIES 4)
               (NOFILEPROPERROR)
               (DEFAULTFILETYPE 'TEXT)
               (\SOCKET.LEAF 35)
               (\SEQUIN.TIMEOUTMAX 10000)
               (\LEAF.IDLETIMEOUT 1800000)
               (\LEAF.CACHETIMEOUT 90000)
               (\LEAF.MAXCACHE 10)
               (\LEAF.RECOVERY.TIMEOUT 600000)
               (\LEAF.MAXLOOKAHEAD 4)
               (\FTPAVAILABLE)
               (UNIXFTPFLG)
               (NONLEAFHOSTS)
               (*UPPER-CASE-FILE-NAMES* T))
        (DECLARE%: EVAL@COMPILE DONTCOPY (COMS * LEAFCOMPILETIMECOMS))
        (INITRECORDS PUPFILESERVER)
        (SYSRECORDS PUPFILESERVER)))



(* ;;; "Support for the Leaf random-access filing protocol")




(* ;; "SEQUIN protocol")

(DECLARE%: EVAL@COMPILE DONTCOPY 

(RPAQQ SEQUINCOMS
       ((RECORDS SEQUINPACKET SEQUIN)
        (CONSTANTS * SEQUINOPS)
        (CONSTANTS * SEQUINSTATES)
        (CONSTANTS (\SC.EQUAL 0)
               (\SC.PREVIOUS 1)
               (\SC.DUPLICATE 2)
               (\SC.AHEAD 3)
               (\SC.OUTOFRANGE 4)
               (\PT.SEQUIN 260Q)
               (\SS.NOSOCKET 10Q)
               (\SEQUIN.DEFAULT.ALLOCATION 12Q)
               (\SEQUIN.DEFAULT.RETRANSMITMAX 5))
        (MACROS SEQUINOP)))
(DECLARE%: EVAL@COMPILE

(ACCESSFNS SEQUINPACKET ((SEQUINSTART (fetch PUPBASE of DATUM)))
                        (BLOCKRECORD SEQUINSTART ((NIL 2 WORD)
                                                             (* ; "Pup length, typeword")
                                                  (ALLOCATE BYTE)
                                                  (RECEIVESEQ BYTE)
                                                  (SEQCONTROL BYTE)
                                                  (SENDSEQ BYTE)
                                                             (* ; 
                                                      "Sequin uses ID fields of PUP for control info")
                                                  )))

(DATATYPE SEQUIN (
                  (* ;; "First: stuff used by SEQUIN level")

                  (SEQNAME POINTER)                          (* ; "Name of partner")
                  (SEQFRNPORT POINTER)                       (* ; "Foreign socket")
                  (SEQSOCKET POINTER)                        (* ; "Local socket")
                  (SEQSTATE BYTE)                            (* ; "Sequin connection state")
                  (MYSENDSEQ BYTE)                           (* ; 
       "Number I will next send.  These must be byte fields so that they will wrap around correctly!")
                  (MYRECEIVESEQ BYTE)                        (* ; 
               "Number I next expect to receive, i.e.  Partner's Send number of first unacked packet")
                  (LASTACKEDSEQ BYTE)                        (* ; 
   "Last Receive seq from partner: all packets with sequence numbers before this one have been acked")
                  (SEQOUTALLOC WORD)                         (* ; 
                      "Output allocation: the number of packets I may send without their being acked")
                  (SEQINALLOC WORD)                          (* ; 
                                                           "Input allocation: what I tell my partner")
                  (SEQMAXALLOC WORD)                         (* ; 
                                                       "The largest I will let output allocation get")
                  (%#UNACKEDSEQS WORD)                       (* ; 
                           "Number of data packets we have sent for which no acks have been received")
                  (SEQINPUTQLENGTH WORD)                     (* ; 
                                                            "Number of packets in input (done) queue")
                  (SEQTIMEOUT WORD)                          (* ; "Timeout before retransmission")
                  (SEQBASETIMEOUT WORD)                      (* ; 
                                                             "Timeout for this connection in general")
                  (SEQRETRANSMITMAX WORD)                    (* ; 
                                                    "How many times to retransmit before complaining")
                  (%#SEQRESTARTS WORD)                       (* ; "Some statistical info...")
                  (%#SEQRETRANSMITS WORD)
                  (%#SEQDUPLICATES WORD)
                  (%#SEQTIMEOUTS WORD)
                  (%#SEQTURNOVERS WORD)
                  (SEQRETRANSMITQ POINTER)                   (* ; "Sequin output queue")
                  (SEQTIMER POINTER)
                  (SEQPROCESS POINTER)
                  (SEQIGNOREDUPLICATES FLAG)
                  (SEQRETRANSMITTING FLAG)
                  (SEQCLOSEME FLAG)
                  (SEQCLOSEDFORLOGOUT FLAG)
                  (SEQLASTRESTARTTIMER POINTER)              (* ; 
                                                    "Allows for some aging of the connection timeout")
                  (SEQLASTRESTART POINTER)
                  (SEQRETRANSMITNEXT POINTER)
                  (SEQEVENT POINTER)                         (* ; 
                                 "Signaled when there is input, state changed, or allocation changed")
                  (SEQLOCK POINTER)                          (* ; "Monitor lock for this structure")

                  (* ;; "Second-level functions invoked by SEQUIN")

                  (SEQACKED POINTER)                         (* ; 
                                                             "(PUP SEQUIN) called when PUP is acked")
                  (SEQINPUT POINTER)                         (* ; 
                                                 "(PUP SEQUIN) called when PUP arrives as input data")
                  (SEQBROKEN POINTER)                        (* ; "(SEQUIN PUP) called when a BROKEN sequin arrives (PUP = NIL) or attempt to send PUP on broken connection")
                  (SEQABORTED POINTER)                       (* ; 
                                  "(SEQUIN) called when PUP arrives with outlandish sequence numbers")
                  (SEQTIMEDOUT POINTER)                      (* ; 
                                    "(SEQUIN) called when about to retransmit SEQRETRANSMITMAX times")
                  (SEQCLOSED POINTER)                        (* ; 
           "(SEQUIN) called when a connection is flushed, but before its retransmit queue is flushed")
                  (SEQIDLETIMEOUTCOMPUTER POINTER)           (* ; "Computes timeout before calling SEQIDLEFN when no activity on connection.  T means forever, NIL means don't")
                  (SEQIDLEFN POINTER)                        (* ; 
                        "Called when nothing otherwise is happening, after timeout of SEQIDLETIMEOUT")

                  (* ;; "Stuff used by clients of SEQUIN, in particular, LEAF")

                  (SEQDONEQ POINTER)                         (* ; 
                                                 "Sequins acked but kept around for further handling")
                  (NIL POINTER)
                  (NIL POINTER)
                  (LEAFCACHEDFILE POINTER)                   (* ; 
                                      "Last file accessed, to speed up repeated lookups of same name")
                  (LEAFCACHETIMER POINTER)                   (* ; "To timeout the cache")
                  (LEAFCACHEHITS WORD)
                  (LEAFCACHEMISSES WORD)
                  (LEAFTIMEOUTCOUNT WORD)
                  (LEAFCLOSING FLAG)
                  (LEAFOPENCLOSELOCK POINTER)                (* ; 
                             "Monitor lock to keep GETFILE and CLOSEFILE from stepping on each other")
                  (LEAFABORTBUTTONWINDOW POINTER)
                  (LEAFABORTSTATUS POINTER)
                  (LEAFTIMEOUTSTATUS POINTER)
                  (SEQTIMEDIN POINTER)
                  (NIL POINTER)
                  (SEQOPENERRORHANDLER POINTER)              (* ; 
                                            "(SEQUIN PUP) called on errors trying to open connection")
                  )
                 SEQSTATE _ \SS.UNOPENED SEQOUTALLOC _ 1 SEQINALLOC _ \SEQUIN.DEFAULT.ALLOCATION 
                 SEQRETRANSMITMAX _ \SEQUIN.DEFAULT.RETRANSMITMAX SEQRETRANSMITQ _
                 (NCREATE 'SYSQUEUE)
                 SEQTIMEOUT _ \ETHERTIMEOUT SEQBASETIMEOUT _ \ETHERTIMEOUT SEQTIMER _ (\CREATECELL
                                                                                       \FIXP)
                 SEQLASTRESTARTTIMER _ (\CREATECELL \FIXP)
                 SEQMAXALLOC _ 12Q SEQACKED _ (FUNCTION NILL)
                 SEQBROKEN _ (FUNCTION NILL)
                 SEQABORTED _ (FUNCTION NILL)
                 SEQABORTED _ (FUNCTION NILL)
                 SEQTIMEDOUT _ (FUNCTION NILL)
                 SEQCLOSED _ (FUNCTION NILL)
                 SEQIDLETIMEOUTCOMPUTER _ (FUNCTION NILL)
                 SEQIDLEFN _ (FUNCTION NILL)
                 SEQTIMEDIN _ (FUNCTION NILL)
                 SEQOPENERRORHANDLER _ (FUNCTION NILL)
                 (SYNONYM SEQDONEQ (INPUTQ)))
)

(/DECLAREDATATYPE 'SEQUIN
       '(POINTER POINTER POINTER BYTE BYTE BYTE BYTE WORD WORD WORD WORD WORD WORD WORD WORD WORD 
               WORD WORD WORD WORD POINTER POINTER POINTER FLAG FLAG FLAG FLAG POINTER POINTER 
               POINTER POINTER POINTER POINTER POINTER POINTER POINTER POINTER POINTER POINTER 
               POINTER POINTER POINTER POINTER POINTER POINTER WORD WORD WORD FLAG POINTER POINTER 
               POINTER POINTER POINTER POINTER POINTER)
       '((SEQUIN 0 POINTER)
         (SEQUIN 2 POINTER)
         (SEQUIN 4 POINTER)
         (SEQUIN 6 (BITS . 7))
         (SEQUIN 6 (BITS . 207Q))
         (SEQUIN 7 (BITS . 7))
         (SEQUIN 7 (BITS . 207Q))
         (SEQUIN 10Q (BITS . 17Q))
         (SEQUIN 11Q (BITS . 17Q))
         (SEQUIN 12Q (BITS . 17Q))
         (SEQUIN 13Q (BITS . 17Q))
         (SEQUIN 14Q (BITS . 17Q))
         (SEQUIN 15Q (BITS . 17Q))
         (SEQUIN 16Q (BITS . 17Q))
         (SEQUIN 17Q (BITS . 17Q))
         (SEQUIN 20Q (BITS . 17Q))
         (SEQUIN 21Q (BITS . 17Q))
         (SEQUIN 22Q (BITS . 17Q))
         (SEQUIN 23Q (BITS . 17Q))
         (SEQUIN 24Q (BITS . 17Q))
         (SEQUIN 26Q POINTER)
         (SEQUIN 30Q POINTER)
         (SEQUIN 32Q POINTER)
         (SEQUIN 32Q (FLAGBITS . 0))
         (SEQUIN 32Q (FLAGBITS . 20Q))
         (SEQUIN 32Q (FLAGBITS . 40Q))
         (SEQUIN 32Q (FLAGBITS . 60Q))
         (SEQUIN 34Q POINTER)
         (SEQUIN 36Q POINTER)
         (SEQUIN 40Q POINTER)
         (SEQUIN 42Q POINTER)
         (SEQUIN 44Q POINTER)
         (SEQUIN 46Q POINTER)
         (SEQUIN 50Q POINTER)
         (SEQUIN 52Q POINTER)
         (SEQUIN 54Q POINTER)
         (SEQUIN 56Q POINTER)
         (SEQUIN 60Q POINTER)
         (SEQUIN 62Q POINTER)
         (SEQUIN 64Q POINTER)
         (SEQUIN 66Q POINTER)
         (SEQUIN 70Q POINTER)
         (SEQUIN 72Q POINTER)
         (SEQUIN 74Q POINTER)
         (SEQUIN 76Q POINTER)
         (SEQUIN 25Q (BITS . 17Q))
         (SEQUIN 100Q (BITS . 17Q))
         (SEQUIN 101Q (BITS . 17Q))
         (SEQUIN 76Q (FLAGBITS . 0))
         (SEQUIN 102Q POINTER)
         (SEQUIN 104Q POINTER)
         (SEQUIN 106Q POINTER)
         (SEQUIN 110Q POINTER)
         (SEQUIN 112Q POINTER)
         (SEQUIN 114Q POINTER)
         (SEQUIN 116Q POINTER))
       '120Q)

(RPAQQ SEQUINOPS
       ((\SEQUIN.DATA 0)
        (\SEQUIN.ACK 1)
        (\SEQUIN.NOOP 2)
        (\SEQUIN.RESTART 3)
        (\SEQUIN.OPEN 5)
        (\SEQUIN.BREAK 6)
        (\SEQUIN.OBSOLETE.CLOSE 7)
        (\SEQUIN.DESTROY 11Q)
        (\SEQUIN.DALLYING 12Q)
        (\SEQUIN.QUIT 13Q)
        (\SEQUIN.BROKEN 14Q)))
(DECLARE%: EVAL@COMPILE 

(RPAQQ \SEQUIN.DATA 0)

(RPAQQ \SEQUIN.ACK 1)

(RPAQQ \SEQUIN.NOOP 2)

(RPAQQ \SEQUIN.RESTART 3)

(RPAQQ \SEQUIN.OPEN 5)

(RPAQQ \SEQUIN.BREAK 6)

(RPAQQ \SEQUIN.OBSOLETE.CLOSE 7)

(RPAQQ \SEQUIN.DESTROY 11Q)

(RPAQQ \SEQUIN.DALLYING 12Q)

(RPAQQ \SEQUIN.QUIT 13Q)

(RPAQQ \SEQUIN.BROKEN 14Q)


(CONSTANTS (\SEQUIN.DATA 0)
       (\SEQUIN.ACK 1)
       (\SEQUIN.NOOP 2)
       (\SEQUIN.RESTART 3)
       (\SEQUIN.OPEN 5)
       (\SEQUIN.BREAK 6)
       (\SEQUIN.OBSOLETE.CLOSE 7)
       (\SEQUIN.DESTROY 11Q)
       (\SEQUIN.DALLYING 12Q)
       (\SEQUIN.QUIT 13Q)
       (\SEQUIN.BROKEN 14Q))
)

(RPAQQ SEQUINSTATES ((\SS.UNOPENED 0)
                     (\SS.OPEN 1)
                     (\SS.DALLYING 2)
                     (\SS.ABORT 3)
                     (\SS.DESTROYED 4)
                     (\SS.TIMEDOUT 5)
                     (\SS.CLOSING 6)
                     (\SS.OPENING 7)
                     (\SS.CLOSED 10Q)))
(DECLARE%: EVAL@COMPILE 

(RPAQQ \SS.UNOPENED 0)

(RPAQQ \SS.OPEN 1)

(RPAQQ \SS.DALLYING 2)

(RPAQQ \SS.ABORT 3)

(RPAQQ \SS.DESTROYED 4)

(RPAQQ \SS.TIMEDOUT 5)

(RPAQQ \SS.CLOSING 6)

(RPAQQ \SS.OPENING 7)

(RPAQQ \SS.CLOSED 10Q)


(CONSTANTS (\SS.UNOPENED 0)
       (\SS.OPEN 1)
       (\SS.DALLYING 2)
       (\SS.ABORT 3)
       (\SS.DESTROYED 4)
       (\SS.TIMEDOUT 5)
       (\SS.CLOSING 6)
       (\SS.OPENING 7)
       (\SS.CLOSED 10Q))
)
(DECLARE%: EVAL@COMPILE 

(RPAQQ \SC.EQUAL 0)

(RPAQQ \SC.PREVIOUS 1)

(RPAQQ \SC.DUPLICATE 2)

(RPAQQ \SC.AHEAD 3)

(RPAQQ \SC.OUTOFRANGE 4)

(RPAQQ \PT.SEQUIN 260Q)

(RPAQQ \SS.NOSOCKET 10Q)

(RPAQQ \SEQUIN.DEFAULT.ALLOCATION 12Q)

(RPAQQ \SEQUIN.DEFAULT.RETRANSMITMAX 5)


(CONSTANTS (\SC.EQUAL 0)
       (\SC.PREVIOUS 1)
       (\SC.DUPLICATE 2)
       (\SC.AHEAD 3)
       (\SC.OUTOFRANGE 4)
       (\PT.SEQUIN 260Q)
       (\SS.NOSOCKET 10Q)
       (\SEQUIN.DEFAULT.ALLOCATION 12Q)
       (\SEQUIN.DEFAULT.RETRANSMITMAX 5))
)
(DECLARE%: EVAL@COMPILE 

(PUTPROPS SEQUINOP MACRO ((SEQ OP . ARGS)
                          (APPLY* (fetch (SEQUIN OP) of SEQ) . ARGS)))
)


(FILESLOAD (LOADCOMP)
       TCPHTE)
)

(/DECLAREDATATYPE 'SEQUIN
       '(POINTER POINTER POINTER BYTE BYTE BYTE BYTE WORD WORD WORD WORD WORD WORD WORD WORD WORD 
               WORD WORD WORD WORD POINTER POINTER POINTER FLAG FLAG FLAG FLAG POINTER POINTER 
               POINTER POINTER POINTER POINTER POINTER POINTER POINTER POINTER POINTER POINTER 
               POINTER POINTER POINTER POINTER POINTER POINTER WORD WORD WORD FLAG POINTER POINTER 
               POINTER POINTER POINTER POINTER POINTER)
       '((SEQUIN 0 POINTER)
         (SEQUIN 2 POINTER)
         (SEQUIN 4 POINTER)
         (SEQUIN 6 (BITS . 7))
         (SEQUIN 6 (BITS . 207Q))
         (SEQUIN 7 (BITS . 7))
         (SEQUIN 7 (BITS . 207Q))
         (SEQUIN 10Q (BITS . 17Q))
         (SEQUIN 11Q (BITS . 17Q))
         (SEQUIN 12Q (BITS . 17Q))
         (SEQUIN 13Q (BITS . 17Q))
         (SEQUIN 14Q (BITS . 17Q))
         (SEQUIN 15Q (BITS . 17Q))
         (SEQUIN 16Q (BITS . 17Q))
         (SEQUIN 17Q (BITS . 17Q))
         (SEQUIN 20Q (BITS . 17Q))
         (SEQUIN 21Q (BITS . 17Q))
         (SEQUIN 22Q (BITS . 17Q))
         (SEQUIN 23Q (BITS . 17Q))
         (SEQUIN 24Q (BITS . 17Q))
         (SEQUIN 26Q POINTER)
         (SEQUIN 30Q POINTER)
         (SEQUIN 32Q POINTER)
         (SEQUIN 32Q (FLAGBITS . 0))
         (SEQUIN 32Q (FLAGBITS . 20Q))
         (SEQUIN 32Q (FLAGBITS . 40Q))
         (SEQUIN 32Q (FLAGBITS . 60Q))
         (SEQUIN 34Q POINTER)
         (SEQUIN 36Q POINTER)
         (SEQUIN 40Q POINTER)
         (SEQUIN 42Q POINTER)
         (SEQUIN 44Q POINTER)
         (SEQUIN 46Q POINTER)
         (SEQUIN 50Q POINTER)
         (SEQUIN 52Q POINTER)
         (SEQUIN 54Q POINTER)
         (SEQUIN 56Q POINTER)
         (SEQUIN 60Q POINTER)
         (SEQUIN 62Q POINTER)
         (SEQUIN 64Q POINTER)
         (SEQUIN 66Q POINTER)
         (SEQUIN 70Q POINTER)
         (SEQUIN 72Q POINTER)
         (SEQUIN 74Q POINTER)
         (SEQUIN 76Q POINTER)
         (SEQUIN 25Q (BITS . 17Q))
         (SEQUIN 100Q (BITS . 17Q))
         (SEQUIN 101Q (BITS . 17Q))
         (SEQUIN 76Q (FLAGBITS . 0))
         (SEQUIN 102Q POINTER)
         (SEQUIN 104Q POINTER)
         (SEQUIN 106Q POINTER)
         (SEQUIN 110Q POINTER)
         (SEQUIN 112Q POINTER)
         (SEQUIN 114Q POINTER)
         (SEQUIN 116Q POINTER))
       '120Q)
(ADDTOVAR SYSTEMRECLST

(DATATYPE SEQUIN ((SEQNAME POINTER)
                  (SEQFRNPORT POINTER)
                  (SEQSOCKET POINTER)
                  (SEQSTATE BYTE)
                  (MYSENDSEQ BYTE)
                  (MYRECEIVESEQ BYTE)
                  (LASTACKEDSEQ BYTE)
                  (SEQOUTALLOC WORD)
                  (SEQINALLOC WORD)
                  (SEQMAXALLOC WORD)
                  (%#UNACKEDSEQS WORD)
                  (SEQINPUTQLENGTH WORD)
                  (SEQTIMEOUT WORD)
                  (SEQBASETIMEOUT WORD)
                  (SEQRETRANSMITMAX WORD)
                  (%#SEQRESTARTS WORD)
                  (%#SEQRETRANSMITS WORD)
                  (%#SEQDUPLICATES WORD)
                  (%#SEQTIMEOUTS WORD)
                  (%#SEQTURNOVERS WORD)
                  (SEQRETRANSMITQ POINTER)
                  (SEQTIMER POINTER)
                  (SEQPROCESS POINTER)
                  (SEQIGNOREDUPLICATES FLAG)
                  (SEQRETRANSMITTING FLAG)
                  (SEQCLOSEME FLAG)
                  (SEQCLOSEDFORLOGOUT FLAG)
                  (SEQLASTRESTARTTIMER POINTER)
                  (SEQLASTRESTART POINTER)
                  (SEQRETRANSMITNEXT POINTER)
                  (SEQEVENT POINTER)
                  (SEQLOCK POINTER)
                  (SEQACKED POINTER)
                  (SEQINPUT POINTER)
                  (SEQBROKEN POINTER)
                  (SEQABORTED POINTER)
                  (SEQTIMEDOUT POINTER)
                  (SEQCLOSED POINTER)
                  (SEQIDLETIMEOUTCOMPUTER POINTER)
                  (SEQIDLEFN POINTER)
                  (SEQDONEQ POINTER)
                  (NIL POINTER)
                  (NIL POINTER)
                  (LEAFCACHEDFILE POINTER)
                  (LEAFCACHETIMER POINTER)
                  (LEAFCACHEHITS WORD)
                  (LEAFCACHEMISSES WORD)
                  (LEAFTIMEOUTCOUNT WORD)
                  (LEAFCLOSING FLAG)
                  (LEAFOPENCLOSELOCK POINTER)
                  (LEAFABORTBUTTONWINDOW POINTER)
                  (LEAFABORTSTATUS POINTER)
                  (LEAFTIMEOUTSTATUS POINTER)
                  (SEQTIMEDIN POINTER)
                  (NIL POINTER)
                  (SEQOPENERRORHANDLER POINTER)))
)
(DEFINEQ

(CLOSESEQUIN
  [LAMBDA (SEQUIN)                                       (* ; "Edited 24-May-91 14:51 by jds")

(* ;;; "Function called to initiate a close connection for a sequin.")

    (PROG NIL
          (\SEQUIN.CLOSE SEQUIN)
      BLK (AWAIT.EVENT (fetch (SEQUIN SEQEVENT) of SEQUIN)
                 \ETHERTIMEOUT)
          (SELECTC (fetch (SEQUIN SEQSTATE) of SEQUIN)
              (\SS.CLOSED (RETURN T))
              (\SS.CLOSING NIL)
              (RETURN NIL))
          (GO BLK])

(INITSEQUIN
  [LAMBDA (SEQUIN PROCNAME)                              (* ; "Edited 24-May-91 14:51 by jds")
    (replace (SEQUIN SEQSOCKET) of SEQUIN with (OPENPUPSOCKET))
    (replace (SEQUIN SEQSTATE) of SEQUIN with \SS.UNOPENED)
    (replace (SEQUIN SEQLOCK) of SEQUIN with (CREATE.MONITORLOCK PROCNAME))
    (replace (SEQUIN SEQEVENT) of SEQUIN with (CREATE.EVENT PROCNAME))
    (replace (SEQUIN MYSENDSEQ) of SEQUIN with 0)
    (replace (SEQUIN MYRECEIVESEQ) of SEQUIN with 0)
    (replace (SEQUIN LASTACKEDSEQ) of SEQUIN with 0)
    (replace (SEQUIN SEQOUTALLOC) of SEQUIN with 1)
    (replace (SEQUIN %#UNACKEDSEQS) of SEQUIN with 0)
    (replace (SEQUIN %#SEQRESTARTS) of SEQUIN with 0)
    (replace (SEQUIN %#SEQDUPLICATES) of SEQUIN with 0)
    (replace (SEQUIN %#SEQTIMEOUTS) of SEQUIN with 0)
    (replace (SEQUIN %#SEQRETRANSMITS) of SEQUIN with 0)
    (replace (SEQUIN %#SEQTURNOVERS) of SEQUIN with 0)
    (replace (SEQUIN SEQPROCESS) of SEQUIN with (ADD.PROCESS (LIST '\SEQUIN.PROCESS 
                                                                               SEQUIN)
                                                                   'NAME PROCNAME 'RESTARTABLE
                                                                   'SYSTEM
                                                                   'AFTEREXIT
                                                                   'DELETE])

(GETSEQUIN
  [LAMBDA (SEQUIN)                                       (* bvm%: "10-APR-83 13:26")

(* ;;; "Function to receive sequin packets on SEQUIN.")

    (PROG (PACKET)
      CL:LOOP
          (COND
             ((SETQ PACKET (\DEQUEUE (fetch (SEQUIN INPUTQ) of SEQUIN)))
                                                             (* (add (fetch (SEQUIN INPUTC) of 
                                                           SEQUIN) -1))
                                                             (* (SEQUIN/CONTROL SEQUIN 
                                                           \SEQUIN.ACK))
              (RETURN PACKET))
             ((EQ (fetch (SEQUIN SEQSTATE) of SEQUIN)
                  \SS.OPEN)
              (BLOCK)
              (GO CL:LOOP))
             (T (RETURN])

(PUTSEQUIN
  [LAMBDA (SEQUIN OPUP DONTWAIT)                         (* ; "Edited 24-May-91 14:52 by jds")
    (PROG1 (WITH.MONITOR (fetch (SEQUIN SEQLOCK) of SEQUIN)
               (until (AND (SELECTC (fetch (SEQUIN SEQSTATE) of SEQUIN)
                                   (\SS.OPEN (replace (SEQUINPACKET SEQCONTROL) of OPUP
                                                with \SEQUIN.DATA)
                                             T)
                                   (\SS.UNOPENED (replace (SEQUIN SEQSTATE) of SEQUIN
                                                    with \SS.OPENING)
                                                 (replace (SEQUINPACKET SEQCONTROL) of OPUP
                                                    with \SEQUIN.OPEN)
                                                 T)
                                   (\SS.OPENING NIL)
                                   (RETURN (PUTSEQUIN (OR (SEQUINOP SEQUIN SEQBROKEN SEQUIN OPUP)
                                                              (RETURN OPUP))
                                                  OPUP)))
                               (ILESSP (fetch (SEQUIN %#UNACKEDSEQS) of SEQUIN)
                                      (fetch (SEQUIN SEQOUTALLOC) of SEQUIN))
                               (ILEQ (fetch (SEQUIN SEQINPUTQLENGTH) of SEQUIN)
                                     (fetch (SEQUIN SEQINALLOC) of SEQUIN))
                               (COND
                                  ((NOT (fetch (SEQUIN SEQRETRANSMITTING) of SEQUIN))
                                   T)
                                  (T 
                                     (* ;; "Should never happen, because \SEQUIN.PROCESS does not relinquish the lock.  Test is here for debugging")

                                     (COND
                                        (LEAFDEBUGFLG (HELP "lock obtained while retransmitting" 
                                                            SEQUIN)))
                                     NIL))) do (COND
                                                      (DONTWAIT (RETURN)))
                                                  (MONITOR.AWAIT.EVENT (fetch (SEQUIN SEQLOCK)
                                                                          of SEQUIN)
                                                         (fetch (SEQUIN SEQEVENT) of SEQUIN)
                                                         \ETHERTIMEOUT)
                  finally (\SEQUIN.PUT SEQUIN OPUP T)
                        (RETURN SEQUIN)))
           (BLOCK])
)
(DEFINEQ

(\SEQUIN.CONTROL
  [LAMBDA (SEQUIN CONTROL PUP)                           (* ; "Edited 23-Dec-87 16:42 by bvm:")

(* ;;; "Routine to send a control sequin of type CONTROL to the other end")

    [COND
       (PUP                                                  (* ; 
                   "Clear source net,host,socket so that SENDPUP will fill them in with the truth.")
            (\CLEARBYTES (LOCF (fetch PUPSOURCE of PUP))
                   0 6))
       (T (SETQ PUP (ALLOCATE.PUP]
    (replace PUPLENGTH of PUP with \PUPOVLEN)
    (replace (SEQUINPACKET SEQCONTROL) of PUP with CONTROL)
    (\SEQUIN.PUT SEQUIN PUP])

(\SEQUIN.PUT
  [LAMBDA (SEQUIN PUP ISDATA)                            (* ; "Edited 24-May-91 14:52 by jds")
    (replace PUPTYPE of PUP with \PT.SEQUIN)
    (replace PUPDEST of PUP with (CAR (fetch (SEQUIN SEQFRNPORT) of SEQUIN)))
    (replace PUPDESTSOCKET of PUP with (CDR (fetch (SEQUIN SEQFRNPORT) of SEQUIN)
                                                        ))
    (UNINTERRUPTABLY
        (PROG ((SENDSEQ (fetch (SEQUIN MYSENDSEQ) of SEQUIN)))
              (replace (SEQUINPACKET RECEIVESEQ) of PUP with (fetch (SEQUIN 
                                                                                         MYRECEIVESEQ
                                                                                           )
                                                                            of SEQUIN))
              (replace (SEQUINPACKET SENDSEQ) of PUP with SENDSEQ)
              [COND
                 (ISDATA [replace (SEQUIN MYSENDSEQ) of SEQUIN
                            with (COND
                                        ((EQ SENDSEQ 377Q)
                                         (add (fetch (SEQUIN %#SEQTURNOVERS) of SEQUIN)
                                                1)
                                         0)
                                        (T (ADD1 SENDSEQ]

                        (* ;; "Data packets increment the send sequence, and we have to keep them around for possible retransmission")

                        (replace EPREQUEUE of PUP with (fetch (SEQUIN SEQRETRANSMITQ)
                                                                      of SEQUIN))
                        (add (fetch (SEQUIN %#UNACKEDSEQS) of SEQUIN)
                               1))
                 (T (replace EPREQUEUE of PUP with 'FREE]
              (replace (SEQUINPACKET ALLOCATE) of PUP with (fetch (SEQUIN SEQINALLOC)
                                                                          of SEQUIN))
              (SENDPUP (fetch (SEQUIN SEQSOCKET) of SEQUIN)
                     PUP)
              (\CLOCK0 (fetch (SEQUIN SEQTIMER) of SEQUIN))

         (* ;; "Make sure the SEQUIN watcher runs.  It might be in its long idle phase, and if no packets arrive on its socket, it won't wake up to notice that remote host is not responding")

              (WAKE.PROCESS (fetch (SEQUIN SEQPROCESS) of SEQUIN))))])

(\SEQUIN.PROCESS
  [LAMBDA (SEQUIN)                                       (* ; "Edited 24-May-91 14:52 by jds")
    (DECLARE (SPECVARS SEQUIN))
    (WITH.MONITOR (fetch (SEQUIN SEQLOCK) of SEQUIN)
        (RESETSAVE NIL (LIST (FUNCTION \SEQUIN.CLEANUP)
                             SEQUIN))
        [PROCESSPROP (THIS.PROCESS)
               'INFOHOOK
               (FUNCTION (LAMBDA NIL
                           (INSPECT SEQUIN]
        (PROG ((SOC (fetch (SEQUIN SEQSOCKET) of SEQUIN))
               (RETRANSQ (fetch (SEQUIN SEQRETRANSMITQ) of SEQUIN))
               (CNT 0)
               RETRANSMITINCREMENT PUP SOCEVENT TIMEOUT REASON)
              (COND
                 ((NOT SOC)                                  (* ; "Sequin was killed")
                  (RETURN)))
              (SETQ SOCEVENT (PUPSOCKETEVENT SOC))
          LP  [COND
                 ((fetch (SEQUIN SEQCLOSEME) of SEQUIN)
                  (RETURN))
                 ((SETQ PUP (GETPUP SOC))
                  (SELECTC (fetch PUPTYPE of PUP)
                      (\PT.SEQUIN (COND
                                     ((\SEQUIN.HANDLE.INPUT SEQUIN PUP)
                                                             (* ; "Something interesting happened")
                                      )))
                      (\PT.ERROR [COND
                                    ((EQ PUPTRACEFLG 'PEEK)
                                     (PRINTPUP PUP 'GET]
                                 [COND
                                    ((NEQ (fetch (SEQUIN SEQSTATE) of SEQUIN)
                                          \SS.OPENING)
                                     (SELECTC (fetch ERRORPUPCODE of PUP)
                                         (\PUPE.NOSOCKET     (* ; 
                                                           "Connection was open and went away?")
                                              (SEQUINOP SEQUIN SEQBROKEN SEQUIN))
                                         NIL))
                                    ((SETQ REASON (SEQUINOP SEQUIN SEQOPENERRORHANDLER SEQUIN PUP))
                                     (RELEASE.PUP PUP)
                                     (RETURN (\SEQUIN.FLUSH.CONNECTION SEQUIN \SS.ABORT REASON]
                                 (RELEASE.PUP PUP))
                      (RELEASE.PUP PUP)))
                 ((fetch (SEQUIN SEQRETRANSMITTING) of SEQUIN)
                  (\SEQUIN.RETRANSMITNEXT SEQUIN))
                 ((EQ (MONITOR.AWAIT.EVENT (fetch (SEQUIN SEQLOCK) of SEQUIN)
                             SOCEVENT
                             (OR (SETQ TIMEOUT (AND (EQ (fetch (SEQUIN %#UNACKEDSEQS)
                                                           of SEQUIN)
                                                        0)
                                                    (NEQ (fetch (SEQUIN SEQSTATE) of SEQUIN)
                                                         \SS.CLOSING)
                                                    (SEQUINOP SEQUIN SEQIDLETIMEOUTCOMPUTER SEQUIN)))
                                 (fetch (SEQUIN SEQTIMEOUT) of SEQUIN)))
                      PSTAT.TIMEDOUT)                        (* ; "Nothing urgent happening")
                  (COND
                     (TIMEOUT (SEQUINOP SEQUIN SEQIDLEFN SEQUIN))
                     (T                                      (* ; "Waiting for acks")
                        (COND
                           ((\CLOCKGREATERP (fetch (SEQUIN SEQTIMER) of SEQUIN)
                                   (fetch (SEQUIN SEQTIMEOUT) of SEQUIN))
                                                             (* ; 
                                          "Haven't seen anything in a while, so prod the other end")
                            (INCLEAFSTAT (fetch (SEQUIN %#SEQTIMEOUTS) of SEQUIN))
                            [COND
                               ((NEQ (fetch (SEQUIN MYRECEIVESEQ) of SEQUIN)
                                     (fetch (SEQUIN SEQLASTRESTART) of SEQUIN))
                                                             (* ; 
                                        "This is the first time we've had trouble at this sequence")
                                (SETQ CNT 1)
                                (SETQ RETRANSMITINCREMENT (IMAX 3720Q (LRSH (fetch (SEQUIN 
                                                                                           SEQTIMEOUT
                                                                                              )
                                                                               of SEQUIN)
                                                                            1)))
                                (replace (SEQUIN SEQLASTRESTART) of SEQUIN
                                   with (fetch (SEQUIN MYRECEIVESEQ) of SEQUIN))
                                (SETUPTIMER 0 (fetch (SEQUIN SEQLASTRESTARTTIMER) of SEQUIN))
                                )
                               (T (SEQUINOP SEQUIN SEQTIMEDOUT SEQUIN (add CNT 1))
                                  (COND
                                     ((fetch (SEQUIN SEQCLOSEME) of SEQUIN)
                                                             (* ; 
                                                        "In case SEQTIMEDOUT closed the connection")
                                      (RETURN]
                            (COND
                               ((ILESSP (fetch (SEQUIN SEQTIMEOUT) of SEQUIN)
                                       \SEQUIN.TIMEOUTMAX)
                                (add (fetch (SEQUIN SEQTIMEOUT) of SEQUIN)
                                       RETRANSMITINCREMENT)))
                            (COND
                               ((EQ (fetch (SEQUIN SEQSTATE) of SEQUIN)
                                    \SS.CLOSING)
                                (\SEQUIN.CONTROL SEQUIN \SEQUIN.DESTROY))
                               ((EQ (fetch (SEQUIN %#UNACKEDSEQS) of SEQUIN)
                                    1)                       (* ; 
                                                          "Only one thing in queue, just resend it")
                                (\SEQUIN.RETRANSMIT SEQUIN))
                               (T                            (* ; 
       "All our stuff is acked, but client is still waiting for something;  or more than one thing")
                                  (\SEQUIN.CONTROL SEQUIN \SEQUIN.NOOP]
              (BLOCK)
              (GO LP)))])

(\SEQUIN.CLOSE
  [LAMBDA (SEQUIN)                                       (* ; "Edited 24-May-91 14:52 by jds")
    (WITH.MONITOR (fetch (SEQUIN SEQLOCK) of SEQUIN)
        (COND
           ((EQ (fetch (SEQUIN SEQSTATE) of SEQUIN)
                \SS.OPEN)
            (replace (SEQUIN SEQSTATE) of SEQUIN with \SS.CLOSING)
            (\SEQUIN.CONTROL SEQUIN \SEQUIN.DESTROY)
            T)))])

(\SEQUIN.FLUSH.CONNECTION
  [LAMBDA (SEQUIN FINALSTATE REASON)                     (* ; "Edited 24-May-91 14:52 by jds")

(* ;;; "Close a sequin connection")

    (PROG ((PROC (fetch (SEQUIN SEQPROCESS) of SEQUIN)))
          (COND
             ((NULL PROC)                                    (* ; "Cleanup has already been done")
              (RETURN)))
          (\SEQUIN.FLUSH.RETRANSMIT SEQUIN)
          (replace (SEQUIN SEQSTATE) of SEQUIN with (OR FINALSTATE \SS.ABORT))
          (NOTIFY.EVENT (fetch (SEQUIN SEQEVENT) of SEQUIN))
          (CLOSEPUPSOCKET (fetch (SEQUIN SEQSOCKET) of SEQUIN))
          (replace (SEQUIN SEQSOCKET) of SEQUIN with NIL)
          (replace (SEQUIN SEQPROCESS) of SEQUIN with NIL)
          (SEQUINOP SEQUIN SEQCLOSED SEQUIN FINALSTATE REASON)
          (COND
             ((NEQ PROC (THIS.PROCESS))
              (DEL.PROCESS PROC))
             (T (replace (SEQUIN SEQCLOSEME) of SEQUIN with T])

(\SEQUIN.CLEANUP
  [LAMBDA (SEQUIN)                                       (* ; "Edited 24-May-91 14:52 by jds")

    (* ;; "Called via RESETSAVE by Sequin process to perform cleanup if the sequin watcher is killed unexpectedly.  Important thing is that we not do this on HARDRESET")

    (SELECTQ RESETSTATE
        ((ERROR RESET) 
             (COND
                ((EQ (fetch (SEQUIN SEQSTATE) of SEQUIN)
                     \SS.OPEN)
                 (\SEQUIN.CONTROL SEQUIN \SEQUIN.BROKEN)))
             (\SEQUIN.FLUSH.CONNECTION SEQUIN \SS.ABORT))
        NIL])

(\SEQUIN.FLUSH.RETRANSMIT
  [LAMBDA (SEQUIN)                                       (* ; "Edited 24-May-91 14:52 by jds")
    (PROG ((REPUP (fetch (SEQUIN SEQRETRANSMITNEXT) of SEQUIN)))
          (COND
             (REPUP (replace (SEQUIN SEQRETRANSMITNEXT) of SEQUIN with NIL)
                    (while REPUP do (\ENQUEUE (fetch (SEQUIN SEQRETRANSMITQ) of
                                                                                         SEQUIN)
                                                   (PROG1 REPUP
                                                       (SETQ REPUP (fetch EPLINK of REPUP)))])

(\SEQUIN.COMPARE
  [LAMBDA (X Y)                                          (* bvm%: " 6-Jan-85 00:14")

(* ;;; "Function to return sequence comparison on received pups")

    (PROG ((DIF (LOGAND (IDIFFERENCE X Y)
                       377Q)))
          (RETURN (COND
                     ((EQ DIF 0)
                      \SC.EQUAL)
                     ((EQ DIF 377Q)
                      \SC.PREVIOUS)
                     ((IGEQ DIF 300Q)
                      \SC.DUPLICATE)
                     ((ILEQ DIF 100Q)
                      \SC.AHEAD)
                     (T \SC.OUTOFRANGE])

(\SEQUIN.HANDLE.INPUT
  [LAMBDA (SEQUIN PUP)                                   (* ; "Edited 24-May-91 14:52 by jds")

(* ;;; "Function to handle input pup.  Checks that sequence numbers are sensible, takes appropriate action if retransmission needed or releases packets that are hereby acked.  Hands new data packets off to next-level protocol")

    (PROG (ALLOC NEWACKSEQ)
          (COND
             ((NEQ (fetch (PUP PUPTYPE) of PUP)
                   \PT.SEQUIN)
              (RELEASE.PUP PUP)
              (RETURN))
             ((EQ (fetch (SEQUINPACKET SEQCONTROL) of PUP)
                  \SEQUIN.BROKEN)
              (SEQUINOP SEQUIN SEQBROKEN SEQUIN)
              (RELEASE.PUP PUP)
              (RETURN)))
          (SELECTC (\SEQUIN.COMPARE (fetch (SEQUINPACKET SENDSEQ) of PUP)
                          (fetch (SEQUIN MYRECEIVESEQ) of SEQUIN))
              (\SC.OUTOFRANGE 
                   (RETURN (\SEQUIN.OUT.OF.THE.BLUE SEQUIN PUP)))
              (\SC.AHEAD                                     (* ; 
                                      "Partner got ahead, ask for retransmission from MYRECEIVESEQ")
                         (COND
                            ((NEQ (fetch (SEQUINPACKET SEQCONTROL) of PUP)
                                  \SEQUIN.RESTART)

                             (* ;; "Don't get into a RESTART loop! Do the retransmit requested by partner and hope that things get better")

                             (\SEQUIN.CONTROL SEQUIN \SEQUIN.RESTART)
                             (RELEASE.PUP PUP)
                             (RETURN))))
              (\SC.DUPLICATE                                 (* ; "Nothing new, drop it")
                             (GO DUPLICATE))
              (\SC.PREVIOUS                                  (* ; 
                                       "Retransmission of last packet is simple way to get restart")
                            (COND
                               ((NOT (fetch (SEQUIN SEQIGNOREDUPLICATES) of SEQUIN))
                                (replace (SEQUINPACKET SEQCONTROL) of PUP with 
                                                                                      \SEQUIN.RESTART
                                       ))
                               ((EQ (fetch (SEQUINPACKET SEQCONTROL) of PUP)
                                    \SEQUIN.DALLYING)

                                (* ;; "KLUDGE!!! To work around bug in Twenex Leaf server.  Remove this when server is fixed for enough people")

                                NIL)
                               (T (GO DUPLICATE))))
              NIL)
          [COND
             [(EQ (SETQ ALLOC (fetch (SEQUINPACKET ALLOCATE) of PUP))
                  0)
              (COND
                 ((ILESSP (fetch (SEQUIN SEQINPUTQLENGTH) of SEQUIN)
                         1)

                  (* ;; "Allocation = 0 normally defaults to 1;  however, in rare cases, my partner has actually decremented its allocation below 1, meaning I can't send ANY packets.")

                  (SETQ ALLOC 1]
             ((IGREATERP ALLOC (fetch (SEQUIN SEQMAXALLOC) of SEQUIN))
              (SETQ ALLOC (fetch (SEQUIN SEQMAXALLOC) of SEQUIN]
          [COND
             ((NEQ (fetch (SEQUIN SEQOUTALLOC) of SEQUIN)
                   ALLOC)
              (replace (SEQUIN SEQOUTALLOC) of SEQUIN with ALLOC)
                                                             (* ; 
                                         "Our allocation changed, maybe someone is waiting to send")
              (NOTIFY.EVENT (fetch (SEQUIN SEQEVENT) of SEQUIN]
          (SELECTC (\SEQUIN.COMPARE (SETQ NEWACKSEQ (fetch (SEQUINPACKET RECEIVESEQ)
                                                           of PUP))
                          (fetch (SEQUIN LASTACKEDSEQ) of SEQUIN))
              (\SC.OUTOFRANGE 
                   (RETURN (\SEQUIN.OUT.OF.THE.BLUE SEQUIN PUP)))
              ((LIST \SC.DUPLICATE \SC.PREVIOUS) 
                   (GO DUPLICATE))
              (\SC.AHEAD                                     (* ; 
                                                           "Release packets acked by this pup")
                         (\SEQUIN.HANDLE.ACK SEQUIN NEWACKSEQ))
              NIL)
          (SELECTC (fetch (SEQUINPACKET SEQCONTROL) of PUP)
              (\SEQUIN.DATA (UNINTERRUPTABLY
                                (COND
                                   ((EQ (fetch (SEQUIN SEQSTATE) of SEQUIN)
                                        \SS.OPENING)
                                    (replace (SEQUIN SEQSTATE) of SEQUIN with \SS.OPEN)))
                                (add (fetch (SEQUIN MYRECEIVESEQ) of SEQUIN)
                                       1)
                                (SEQUINOP SEQUIN SEQINPUT PUP SEQUIN)
                                (NOTIFY.EVENT (fetch (SEQUIN SEQEVENT) of SEQUIN)))
                            (COND
                               ((NEQ (fetch (SEQUIN SEQTIMEOUT) of SEQUIN)
                                     (fetch (SEQUIN SEQBASETIMEOUT) of SEQUIN))
                                (replace (SEQUIN SEQTIMEOUT) of SEQUIN
                                   with (fetch (SEQUIN SEQBASETIMEOUT) of SEQUIN))
                                (SEQUINOP SEQUIN SEQTIMEDIN SEQUIN)))
                                                             (* ; 
                                           "Set timeout back to normal now that we have a response")
                            (RETURN T))
              (\SEQUIN.RESTART 
                   (INCLEAFSTAT (fetch (SEQUIN %#SEQRESTARTS) of SEQUIN))
                   (\SEQUIN.RETRANSMIT SEQUIN))
              (\SEQUIN.DALLYING                              (* ; "Only sequin Users get this")
                   (COND
                      ((EQ (fetch (SEQUIN SEQSTATE) of SEQUIN)
                           \SS.CLOSING)
                       (\SEQUIN.CONTROL SEQUIN \SEQUIN.QUIT)
                       (\SEQUIN.FLUSH.CONNECTION SEQUIN \SS.CLOSED))))
              (\SEQUIN.DESTROY                               (* ; 
                                                           "Only sequin Servers get this or QUIT")
                   (\SEQUIN.CONTROL SEQUIN \SEQUIN.DALLYING)
                   (replace (SEQUIN SEQSTATE) of SEQUIN with \SS.DALLYING))
              (\SEQUIN.QUIT (COND
                               ((EQ (fetch (SEQUIN SEQSTATE) of SEQUIN)
                                    \SS.DALLYING)
                                (\SEQUIN.FLUSH.CONNECTION SEQUIN \SS.CLOSED))))
              NIL)
          (RELEASE.PUP PUP)
          (RETURN T)
      DUPLICATE
          (INCLEAFSTAT (fetch (SEQUIN %#SEQDUPLICATES) of SEQUIN))
          (RELEASE.PUP PUP)
          (RETURN])

(\SEQUIN.OUT.OF.THE.BLUE
  [LAMBDA (SEQUIN PUP)                                   (* bvm%: "27-JUL-83 22:29")

(* ;;; "Called when PUP arrives on SEQUIN with outlandish sequence numbers")

         (* * (replace (SEQUIN SEQSTATE) of SEQUIN with \SS.ABORT)
       (\SEQUIN.CONTROL SEQUIN \SEQUIN.BROKEN)
       (SEQUINOP SEQUIN SEQABORTED SEQUIN) (RELEASE.PUP PUP))

    NIL])

(\SEQUIN.HANDLE.ACK
  [LAMBDA (SEQUIN ACKSEQ)                                (* ; "Edited 24-May-91 14:52 by jds")

(* ;;; "Function to dispose of Pups on the output queue which have been acknowledged by a Receive sequence of ACKSEQ")

    (bind (QUEUE _ (fetch (SEQUIN SEQRETRANSMITQ) of SEQUIN))
           NEWACKSEQ PUP do                              (* ; 
                                                  "All packets up to ACKSEQ-1 are now acknowledged")
                               (COND
                                  ((NULL (SETQ PUP (\QUEUEHEAD QUEUE)))
                                                             (* ; 
                                                "Pup hasn't come back from transmission yet;  wait")
                                   (COND
                                      ((fetch (SEQUIN SEQRETRANSMITTING) of SEQUIN)
                                                             (* ; 
                                "Pup hasn't come back yet because we haven't sent it! Send another")
                                       (\SEQUIN.RETRANSMITNEXT SEQUIN)))
                                   (BLOCK))
                                  ((UNINTERRUPTABLY
                                       (\DEQUEUE QUEUE)
                                       (add (fetch (SEQUIN %#UNACKEDSEQS) of SEQUIN)
                                              -1)
                                       (replace (SEQUIN LASTACKEDSEQ) of SEQUIN
                                          with (SETQ NEWACKSEQ (LOGAND (ADD1 (fetch
                                                                                  (SEQUINPACKET
                                                                                   SENDSEQ)
                                                                                    of PUP))
                                                                          377Q)))
                                       (SEQUINOP SEQUIN SEQACKED PUP SEQUIN)
                                       (EQ NEWACKSEQ ACKSEQ))
                                   (RETURN])

(\SEQUIN.RETRANSMIT
  [LAMBDA (SEQUIN)                                       (* ; "Edited 24-May-91 14:52 by jds")

(* ;;; "Routine to retransmit output sequins")

    (OR (fetch (SEQUIN SEQRETRANSMITTING) of SEQUIN)
        (PROG ((QUEUE (fetch (SEQUIN SEQRETRANSMITQ) of SEQUIN)))
              (COND
                 ((NULL (fetch SYSQUEUEHEAD of QUEUE))
                  (RETURN T)))
              (while (NEQ (LOGAND (ADD1 (fetch (SEQUINPACKET SENDSEQ)
                                               of (fetch SYSQUEUETAIL of QUEUE)))
                                     377Q)
                              (fetch (SEQUIN MYSENDSEQ) of SEQUIN)) do 

                                          (* ;; "Not all of our packets have been transmitted yet;  don't restart now or our retransmit queue will get out of order")

                                                                                  (BLOCK))
              (UNINTERRUPTABLY
                  (replace (SEQUIN SEQRETRANSMITNEXT) of SEQUIN with (fetch 
                                                                                        SYSQUEUEHEAD
                                                                                    of QUEUE))
                  (replace SYSQUEUEHEAD of QUEUE with (replace SYSQUEUETAIL
                                                                     of QUEUE with NIL))
                                                             (* ; 
                "Detach chain of pups from retransmit queue so that they can return there normally")
                  (replace (SEQUIN SEQRETRANSMITTING) of SEQUIN with T))])

(\SEQUIN.RETRANSMITNEXT
  [LAMBDA (SEQUIN)                                       (* ; "Edited 24-May-91 14:52 by jds")
    (PROG ((NEXTPUP (fetch (SEQUIN SEQRETRANSMITNEXT) of SEQUIN)))
          (replace EPREQUEUE of NEXTPUP with (fetch (SEQUIN SEQRETRANSMITQ)
                                                            of SEQUIN))
          (replace (SEQUINPACKET RECEIVESEQ) of NEXTPUP with (fetch (SEQUIN 
                                                                                         MYRECEIVESEQ
                                                                                           )
                                                                            of SEQUIN))
          (replace (SEQUINPACKET ALLOCATE) of NEXTPUP with (fetch (SEQUIN SEQINALLOC)
                                                                          of SEQUIN))
          [SENDPUP (fetch (SEQUIN SEQSOCKET) of SEQUIN)
                 (PROG1 NEXTPUP
                     (OR (replace (SEQUIN SEQRETRANSMITNEXT) of SEQUIN
                            with (fetch EPLINK of NEXTPUP))
                         (replace (SEQUIN SEQRETRANSMITTING) of SEQUIN with NIL)))]
          (add (fetch (SEQUIN %#SEQRETRANSMITS) of SEQUIN)
                 1])
)



(* ;; "LEAF device operations")

(DEFINEQ

(\LEAF.CLOSEFILE
  [LAMBDA (STREAM CONNECTION LEAFHANDLE FORCE)(* ; 
                                                "Edited  2-Nov-92 03:35 by sybalsky:mv:envos")

(* ;;; "Closes the file open on this LEAF connection.  CONNECTION and LEAFHANDLE are obtained from STREAM if necessary;  else STREAM may be NIL")

    (PROG (OPUP DATA (INTERNAL CONNECTION))
          [COND
             (STREAM (\CLEARMAP STREAM)
                    (OR (SETQ CONNECTION (fetch (LEAFSTREAM LEAFCONNECTION) of STREAM))
                        (LISPERROR "FILE NOT OPEN" STREAM))
                    (COND
                       ((WITH.MONITOR (fetch (SEQUIN LEAFOPENCLOSELOCK) of CONNECTION)
                            [COND
                               ((EQ (fetch (SEQUIN SEQSTATE) of CONNECTION)
                                    \SS.OPEN)
                                (COND
                                   [(AND (NOT FORCE)
                                         (NOT (DIRTYABLE STREAM)))
                                                             (* ; 
            "Don't really close it;  keep it around in case someone wants to look at it again soon")
                                    (OR INTERNAL (replace (LEAFSTREAM LEAFREALLYOPEN)
                                                    of STREAM with NIL))

                                    (* ;; "If this is a call from CLOSEF then mark the stream as `really' closed, so that we know we can close it later")

                                    (LET ((CACHE (fetch (SEQUIN LEAFCACHEDFILE) of CONNECTION
                                                        )))
                                         (COND
                                            ((NULL CACHE)    (* ; 
                                               "No cache before, so just make this the cached file")
                                             (replace (SEQUIN LEAFCACHEDFILE) of CONNECTION
                                                with STREAM)
                                             T)
                                            ((EQ CACHE STREAM)
                                                             (* ; 
                                                     "Closing the already cached file?  Do nothing")
                                             T)
                                            ((EQ (fetch (STREAM FULLFILENAME) of STREAM)
                                                 (fetch (STREAM FULLFILENAME) of CACHE))

                                 (* ;; "Two streams open on the same file.  Could happen if STREAM was opened with an incomplete filename.  Always prefer to keep the originally cached file around, so fall thru now and close STREAM")

                                             NIL)
                                            (T (replace (SEQUIN LEAFCACHEDFILE) of CONNECTION
                                                  with STREAM)
                                               (COND
                                                  ((fetch (LEAFSTREAM LEAFREALLYOPEN)
                                                      of CACHE)
                                                   T)
                                                  (T         (* ; 
                                     "Close the formerly cached stream if Lisp thinks it is closed")
                                                     (SETQ STREAM CACHE)
                                                     NIL]
                                   ((EQ STREAM (fetch (SEQUIN LEAFCACHEDFILE) of CONNECTION))
                                                             (* ; 
                                                          "We are about to close the cached stream")
                                    (replace (SEQUIN LEAFCACHEDFILE) of CONNECTION
                                       with NIL])
                        (RETURN)))
                    (SETQ LEAFHANDLE (fetch (LEAFSTREAM LEAFHANDLE) of STREAM]
          (COND
             ((EQ (fetch (SEQUIN SEQSTATE) of CONNECTION)
                  \SS.OPEN)                                  (* ; 
                                  "Don't bother sending anything if the connection is already gone")
              (SETQ OPUP (ALLOCATE.PUP))
              (SETQ DATA (fetch PUPCONTENTS of OPUP))
              (replace (LEAFDATA OPWORD) of DATA with (LLSH \LEAFOP.CLOSE \OPCODE.SHIFT))
              (replace (LEAFDATA HANDLE) of DATA with LEAFHANDLE)
              (replace (LEAFDATA LEAFLENGTH) of DATA with \LEN.CLOSEREQUEST)
                                                             (* ; "Note: don't give the stream to the sequin if we are quietly closing the cache, because we don't want this to result in a bogus not responding error")
              (\SENDLEAF CONNECTION OPUP (AND (NEQ FORCE :CACHE)
                                                  STREAM)
                     NIL T)))
          (COND
             (STREAM                                         (* ; "no good anymore")
                    (OR INTERNAL (replace (LEAFSTREAM LEAFREALLYOPEN) of STREAM with
                                                                                        NIL))
                    (replace (LEAFSTREAM LEAFPAGECACHE) of STREAM with NIL)
                    (replace (LEAFSTREAM LEAFCONNECTION) of STREAM with NIL])

(\LEAF.DELETEFILE
  [LAMBDA (FILENAME DEV)                      (* ; 
                                                "Edited  2-Nov-92 03:35 by sybalsky:mv:envos")
    (PROG ((OPUP (ALLOCATE.PUP))
           (STREAM (\LEAF.GETFILE DEV FILENAME 'OUTPUT 'OLDEST T 'NODATES))
           DATA IPUP)
          (RETURN (COND
                     (STREAM (SETQ DATA (fetch PUPCONTENTS of OPUP))
                            (replace (LEAFDATA OPWORD) of DATA with (LLSH \LEAFOP.DELETE
                                                                                      \OPCODE.SHIFT))
                            (replace (LEAFDATA HANDLE) of DATA with (fetch
                                                                                 (LEAFSTREAM 
                                                                                        LEAFHANDLE)
                                                                                   of STREAM))
                            (replace (LEAFDATA LEAFLENGTH) of DATA with \LEN.CLOSEREQUEST
                                   )
                            (COND
                               ((SETQ IPUP (\SENDLEAF (fetch (LEAFSTREAM LEAFCONNECTION)
                                                             of STREAM)
                                                  OPUP STREAM))
                                (RELEASE.PUP IPUP)
                                (replace (LEAFSTREAM LEAFCONNECTION) of STREAM with
                                                                                       NIL)
                                                             (* ; 
                                                           "The leaf file connection is now gone")
                                (fetch (STREAM FULLFILENAME) of STREAM])

(\LEAF.DEVICEP
  [LAMBDA (HOST LEAFDEV)                                 (* ; "Edited 26-Apr-90 11:56 by nm")

(* ;;; "Returns the device corresponding to this HOST, or NIL if it is an illegal leaf host")

    (PROG (NAME DEVICE SEQUIN CONN)
          (RETURN (COND
                     ([AND (STRPOS "DSK" HOST 1 NIL T NIL UPPERCASEARRAY)
                           (for I from 4 to (NCHARS HOST)
                              always (SMALLP (NTHCHAR HOST I]
                                                             (* ; 
                                                          "Kludge: Name of form DSKn: don't bother")
                      NIL)
                     ((STRPOS '%: HOST)                      (* ; 
                                 "NS host, skip it.  Would be nice to have more orderly name tests")
                      NIL)
                     ((AND (EQL \MACHINETYPE \MAIKO)
                           (STRPOS "UNIX" HOST 1 NIL T NIL UPPERCASEARRAY))
                                                             (* ; 
                                                  "Maiko uses UNIX as a name of local file system.")
                      NIL)
                     ((NULL (SETQ NAME (\CANONICAL.HOSTNAME HOST)))
                      NIL)
                     ((NULL LEAFDEV)                         (* ; 
                                                       "Called as predicate, don't try to open one")
                      NAME)
                     ((AND (NEQ NAME HOST)
                           (SETQ DEVICE (\GETDEVICEFROMNAME NAME T T)))
                      DEVICE)
                     ((NULL (SETQ SEQUIN (\OPENLEAFCONNECTION NAME)))
                      NIL)
                     ((type? SEQUIN SEQUIN)
                      [\DEFINEDEVICE NAME (SETQ DEVICE
                                           (\MAKE.PMAP.DEVICE (create FDEV
                                                                     DEVICENAME _ NAME
                                                                     CLOSEFILE _
                                                                     (FUNCTION \LEAF.CLOSEFILE)
                                                                     DELETEFILE _
                                                                     (FUNCTION \LEAF.DELETEFILE)
                                                                     GETFILEINFO _
                                                                     (FUNCTION \LEAF.GETFILEINFO)
                                                                     OPENFILE _
                                                                     (FUNCTION \LEAF.OPENFILE)
                                                                     READPAGES _
                                                                     (FUNCTION \LEAF.READPAGES)
                                                                     WRITEPAGES _
                                                                     (FUNCTION \LEAF.WRITEPAGES)
                                                                     SETFILEINFO _
                                                                     (FUNCTION \LEAF.SETFILEINFO)
                                                                     TRUNCATEFILE _
                                                                     (FUNCTION \LEAF.TRUNCATEFILE)
                                                                     GETFILENAME _
                                                                     (FUNCTION \LEAF.GETFILENAME)
                                                                     REOPENFILE _
                                                                     (FUNCTION \LEAF.REOPENFILE)
                                                                     GENERATEFILES _
                                                                     (FUNCTION \LEAF.GENERATEFILES)
                                                                     EVENTFN _ (FUNCTION 
                                                                                \LEAF.EVENTFN)
                                                                     DIRECTORYNAMEP _
                                                                     (FUNCTION \LEAF.DIRECTORYNAMEP)
                                                                     HOSTNAMEP _
                                                                     (FUNCTION NILL)
                                                                     RENAMEFILE _
                                                                     (FUNCTION \LEAF.RENAMEFILE)
                                                                     DEVICEINFO _
                                                                     (create PUPFILESERVER
                                                                            PFSNAME _ NAME
                                                                            PFSOSTYPE _
                                                                            (GETHOSTINFO
                                                                             NAME
                                                                             'OSTYPE)
                                                                            PFSLEAFSEQUIN _ SEQUIN)
                                                                     FORCEOUTPUT _
                                                                     (FUNCTION \LEAF.FORCEOUTPUT)
                                                                     OPENP _ (FUNCTION \GENERIC.OPENP
                                                                              )
                                                                     REGISTERFILE _
                                                                     (FUNCTION \ADD-OPEN-STREAM)
                                                                     UNREGISTERFILE _
                                                                     (FUNCTION 
                                                                      \GENERIC-UNREGISTER-STREAM)
                                                                     BREAKCONNECTION _
                                                                     (FUNCTION \LEAF.BREAKCONNECTION]
                      DEVICE)
                     ((AND \FTPAVAILABLE (SETQ CONN (\FTP.OPEN.CONNECTION NAME)))
                      (\RELEASE.FTPCONNECTION CONN)
                      \FTPFDEV])

(\LEAF.RECONNECT
  [LAMBDA (DEVICE OLDONLY)                               (* ; "Edited 24-May-91 15:11 by jds")
    (WITH.MONITOR \LEAFCONNECTIONLOCK
        [PROG ((INFO (fetch DEVICEINFO of DEVICE))
               SEQUIN)
              (RETURN (COND
                         ((AND (SETQ SEQUIN (fetch (PUPFILESERVER PFSLEAFSEQUIN) of INFO))
                               (EQ (fetch (SEQUIN SEQSTATE) of SEQUIN)
                                   \SS.OPEN))
                          SEQUIN)
                         ([AND (NOT OLDONLY)
                               (type? SEQUIN (SETQ SEQUIN (\OPENLEAFCONNECTION
                                                               (fetch (PUPFILESERVER PFSNAME)
                                                                  of INFO]
                          (replace (PUPFILESERVER PFSLEAFSEQUIN) of INFO with SEQUIN)
                          SEQUIN])])

(\LEAF.DIRECTORYNAMEP
  [LAMBDA (HOST/DIR DEV)                                 (* ; "Edited 24-May-91 15:11 by jds")

    (* ;; "True if HOST/DIR is a valid host/directory specification, NIL if not.  We do this by trying to open an unlikely filename on the dir and see if the error we get is 'file not found' or 'invalid directory'")

    (LET (INFO)
         (COND
            ((NULL (UNPACKFILENAME.STRING HOST/DIR 'DIRECTORY))
                                                             (* ; "No directory field--assume is malformed.  Don't do GETFILE below, since that packfilename could coerce a non-directory into a directory")
             NIL)
            ((CL:MEMBER HOST/DIR (fetch (PUPFILESERVER PFSKNOWNDIRS)
                                    of (SETQ INFO (fetch DEVICEINFO of DEV)))
                    :TEST
                    (if (EQ (fetch (PUPFILESERVER PFSOSTYPE) of INFO)
                                'UNIX)
                        then                             (* ; "Stupid case-sensitive")
                              'CL:STRING=
                      else 'STRING-EQUAL))               (* ; 
                                                           "We already know this directory is ok")
             T)
            ((\LEAF.GETFILE DEV (PACKFILENAME.STRING 'DIRECTORY HOST/DIR 'NAME "QXZRYU")
                    'INPUT
                    'OLD T 'DIRECTORY)
             (push (fetch (PUPFILESERVER PFSKNOWNDIRS) of INFO)
                    HOST/DIR)                                (* ; 
                                "Returning T tells the caller to canonicalize the host name for me")
             T])

(\LEAF.GENERATEFILES
  [LAMBDA (DEVICE PATTERN DESIREDPROPS OPTIONS)          (* bvm%: "28-Apr-84 00:02")
    (OR (AND \FTPAVAILABLE (\FTP.GENERATEFILES DEVICE PATTERN DESIREDPROPS OPTIONS))
        (\GENERATENOFILES DEVICE PATTERN DESIREDPROPS OPTIONS])

(\LEAF.GETFILE
  [LAMBDA (DEVICE FILENAME ACCESS RECOG NOERROR OPTION OLDSTREAM REALLYOPEN)
                                                  (* ; 
                                                "Edited  2-Nov-92 03:35 by sybalsky:mv:envos")

(* ;;; "Opens FILENAME for indicated ACCESS and RECOG, returning a STREAM, optionally smashing DEADSTREAM, on the resulting file, which is now open.  If NOERROR is T, returns NIL on errors;  if NOERROR is FIND, returns NIL only on file not found errors.  OPTION specifies special way to not really open the file;  choices are --- NAME -- used to get a full file name: in this case, the fullname is returned, and the file is closed on exit --- DIRECTORY -- FILENAME is a directory specification, not a 'real' filename.  Return NIL if the directory doesn't exist, T if it does.")

    (PROG ((DEVINFO (fetch DEVICEINFO of DEVICE))
           CONNECTION MODE FILELENGTH CACHEDSTREAM LEAFHANDLE HOST REMOTENAME NAME/PASS OUTCOME 
           CONNECTNAME/PASS OPUP IPUP DATA)
          (COND
             ((SETQ HOST (\PARSE.REMOTE.FILENAME FILENAME NOERROR DEVICE))
              (SETQ REMOTENAME (CDR HOST))
              (SETQ HOST (CAR HOST)))
             (T (RETURN)))
          (SETQ CONNECTION (fetch (PUPFILESERVER PFSLEAFSEQUIN) of DEVINFO))
      TOP (OR CONNECTION (SETQ CONNECTION (\LEAF.RECONNECT DEVICE))
              (RETURN))
          (COND
             ([AND (fetch (SEQUIN LEAFCACHEDFILE) of CONNECTION)
                   (SETQ OUTCOME
                    (WITH.MONITOR (fetch (SEQUIN LEAFOPENCLOSELOCK) of CONNECTION)
                        [AND (SETQ CACHEDSTREAM (fetch (SEQUIN LEAFCACHEDFILE) of CONNECTION)
                              )
                             (SELECTQ ACCESS
                                 ((NONE INPUT) 
                                      (COND
                                         ((AND (NOT OLDSTREAM)
                                               (EQ (fetch (STREAM FULLFILENAME) of 
                                                                                         CACHEDSTREAM
                                                          )
                                                   FILENAME)
                                               (COND
                                                  ((NOT REALLYOPEN)
                                                   T)
                                                  ((fetch (LEAFSTREAM LEAFREALLYOPEN)
                                                      of CACHEDSTREAM)
                                                             (* ; 
                                    "Asking for a new REAL opening of the file, so don't use cache")
                                                   NIL)
                                                  (T (replace (LEAFSTREAM LEAFREALLYOPEN)
                                                        of CACHEDSTREAM with T)
                                                     T)))    (* ; 
                                    "We already have this file open, and its open state is correct")
                                          (SELECTQ OPTION
                                              (NAME FILENAME)
                                              (DATES (\LEAF.GETFILEDATES CACHEDSTREAM)
                                                     CACHEDSTREAM)
                                              CACHEDSTREAM))))
                                 (COND
                                    ((NOT (fetch (LEAFSTREAM LEAFREALLYOPEN) of CACHEDSTREAM)
                                          )                  (* ; 
                  "Close the cached file in case it is the one we are now trying to open for write")
                                     (replace (SEQUIN LEAFCACHEDFILE) of CONNECTION
                                        with NIL)
                                     (\LEAF.CLOSEFILE CACHEDSTREAM T NIL T)
                                     NIL])]
              (RETURN OUTCOME)))
          (SETQ NAME/PASS (\INTERNAL/GETPASSWORD HOST))
      RETRY
          (SETQ OPUP (ALLOCATE.PUP))
          (SETQ DATA (fetch PUPCONTENTS of OPUP))
          (\CLEARBYTES DATA 0 \LEN.OPENREQUEST)
          (replace (LEAFDATA OPCODE) of DATA with \LEAFOP.OPEN)
          (replace (LEAFDATA OPENMODE) of DATA
             with (+ (SELECTQ ACCESS
                             ((INPUT NONE) 
                                  \LEAF.READBIT)
                             ((OUTPUT APPEND BOTH) 
                                  (+ \LEAF.WRITEBIT \LEAF.EXTENDBIT))
                             (LISPERROR "ILLEGAL ARG" ACCESS))
                         (SELECTQ RECOG
                             (OLD \LEAF.DEFAULT.HIGHEST)
                             (OLD/NEW (+ \LEAF.DEFAULT.HIGHEST \LEAF.CREATEBIT))
                             (NEW (+ \LEAF.DEFAULT.NEXT \LEAF.CREATEBIT))
                             (OLDEST \LEAF.DEFAULT.LOWEST)
                             (NIL (SELECTQ ACCESS
                                      (OUTPUT (+ \LEAF.DEFAULT.NEXT \LEAF.CREATEBIT))
                                      ((INPUT NONE) 
                                           \LEAF.DEFAULT.HIGHEST)
                                      (+ \LEAF.DEFAULT.HIGHEST \LEAF.CREATEBIT)))
                             (LISPERROR "ILLEGAL ARG" RECOG))
                         \LEAF.EXPLICIT.ANY))
          (replace (LEAFDATA LEAFLENGTH) of DATA with \LEN.OPENREQUEST)
          (\ADDLEAFSTRING OPUP (CAR NAME/PASS))
          (\ADDLEAFSTRING OPUP (CDR NAME/PASS)
                 T)
          (\ADDLEAFSTRING OPUP (CAR CONNECTNAME/PASS))   (* ; "Connect name")
          (\ADDLEAFSTRING OPUP (CDR CONNECTNAME/PASS)
                 T)                                          (* ; "Connect password")
          (\ADDLEAFSTRING OPUP REMOTENAME)
          [RETURN (COND
                     ((SETQ IPUP (\SENDLEAF CONNECTION OPUP (if (EQ OPTION 'DIRECTORY)
                                                                    then 
                                                             (* ; 
                                      "Don't reveal that silly name if connection fails to respond")
                                                                          T
                                                                  else FILENAME)
                                        T))
                      (PROG1 [SELECTC (SETQ OUTCOME (fetch (LEAFPACKET LEAFSTATUS) of IPUP))
                                 (\LEAF.GOODSTATUS 
                                      (SETQ FILELENGTH (fetch (LEAFDATA FILEADDRESS)
                                                          of (fetch PUPCONTENTS of IPUP))
                                       )
                                      (SETQ LEAFHANDLE (fetch (LEAFDATA HANDLE)
                                                          of (fetch PUPCONTENTS of IPUP))
                                       )
                                      [COND
                                         ((EQ OPTION 'DIRECTORY)
                                                             (* ; 
                                         "just wanted to know if directory is valid.  Obviously is")
                                          (\LEAF.CLOSEFILE NIL CONNECTION LEAFHANDLE)
                                          T)
                                         (T (COND
                                               ((NOT (PROG1 OLDSTREAM
                                                         (OR OLDSTREAM (SETQ OLDSTREAM
                                                                        (create STREAM
                                                                               DEVICE _ DEVICE)))
                                                         (replace (LEAFSTREAM LEAFCONNECTION)
                                                            of OLDSTREAM with CONNECTION)
                                                         (replace (LEAFSTREAM LEAFHANDLE)
                                                            of OLDSTREAM with LEAFHANDLE)))
                                                (replace (STREAM FULLFILENAME) of OLDSTREAM
                                                   with (OR (\LEAF.READFILENAME OLDSTREAM 
                                                                       DEVINFO)
                                                                FILENAME)))
                                               (T (replace (LEAFSTREAM LEAFPAGECACHE)
                                                     of OLDSTREAM with NIL)))
                                            [COND
                                               ((EQ ACCESS 'OUTPUT)
                                                             (* ; 
                                      "Note: OUTPUT means there is no file to start with! so EOF=0")
                                                (replace (STREAM EPAGE) of OLDSTREAM
                                                   with (replace (STREAM EOFFSET)
                                                               of OLDSTREAM with 0)))
                                               (T (replace (STREAM EPAGE) of OLDSTREAM
                                                     with (fetch (BYTEPTR PAGE) of 
                                                                                           FILELENGTH
                                                                     ))
                                                  (replace (STREAM EOFFSET) of OLDSTREAM
                                                     with (fetch (BYTEPTR OFFSET)
                                                                 of FILELENGTH]
                                            (COND
                                               ((EQ OPTION 'NAME)
                                                (PROG1 (fetch (STREAM FULLFILENAME) of 
                                                                                            OLDSTREAM
                                                              )
                                                       (\LEAF.CLOSEFILE OLDSTREAM T)))
                                               (T (COND
                                                     ((OR (EQ OPTION 'DATES)
                                                          (NEQ ACCESS 'NONE))
                                                      (\LEAF.GETFILEDATES OLDSTREAM T)))
                                                  OLDSTREAM])
                                 (\PASSWORD.ERRORS           (* ; "password error")
                                      (COND
                                         ((SETQ NAME/PASS (\FIXPASSWORD OUTCOME CONNECTION))
                                          (GO RETRY))
                                         (T (GO CAUSE.ERROR))))
                                 (\CONNECT.PASSWORD.ERRORS   (* ; "Connect info bad, try again")
                                      (COND
                                         ([SETQ CONNECTNAME/PASS (\FIXPASSWORD
                                                                  OUTCOME CONNECTION
                                                                  (OR (CAR CONNECTNAME/PASS)
                                                                      (\LEAF.DIRECTORYNAMEONLY
                                                                       FILENAME]
                                          (GO RETRY))
                                         (T (GO CAUSE.ERROR))))
                                 ((CONS \IFSERROR.INVALID.DIRECTORY \IFSERROR.MALFORMED) 
                                      (COND
                                         ((OR (EQ OPTION 'DIRECTORY)
                                              NOERROR)
                                          NIL)
                                         (T (\LEAF.ERROR IPUP FILENAME CONNECTION))))
                                 (\LEAF.BROKEN.STATUS 
                                      (SETQ CONNECTION)
                                      (GO TOP))
                                 (COND
                                    ((EQ OPTION 'DIRECTORY)  (* ; 
                   "Open didn't barf on invalid directory, so I assume at least that much was okay")
                                     T)
                                    [(EQ OUTCOME \IFSERROR.PROTECTION)
                                     (COND
                                        ([AND (NULL (CDR CONNECTNAME/PASS))
                                              (SETQ CONNECTNAME/PASS (\FIXPASSWORD OUTCOME 
                                                                            CONNECTION (
                                                                            \LEAF.DIRECTORYNAMEONLY
                                                                                        FILENAME]

                                 (* ;; "File protected, but we got a connect password.  Don't do this if we already had a connect password, since then the error is 'incorrect connect password' and this protection error means there's no hope")

                                         (GO RETRY))
                                        (T (GO CAUSE.ERROR]
                                    ((OR (EQ NOERROR T)
                                         (EQ OUTCOME \IFSERROR.FILE.NOT.FOUND))
                                     NIL)
                                    (T (\LEAF.ERROR IPUP FILENAME CONNECTION]
                             (RELEASE.PUP IPUP]
      CAUSE.ERROR
          (RELEASE.PUP IPUP)
          (RETURN (COND
                     ((NEQ NOERROR T)
                      (SELECTC OUTCOME
                          (\IFSERROR.FILE.NOT.FOUND 
                               NIL)
                          ((CONS \IFSERROR.PROTECTION \CONNECT.PASSWORD.ERRORS) 
                               (LISPERROR "PROTECTION VIOLATION" FILENAME))
                          (LISPERROR "FILE WON'T OPEN" FILENAME])

(\PARSE.REMOTE.FILENAME
  [LAMBDA (FILENAME NOERROR DEVICE)                      (* ; "Edited 11-Jan-88 16:12 by bvm")

    (* ;; "Parses FILENAME as a dotted pair of host and device-specific name, the latter something we can give to the remote host")

    (PROG ((OSTYPE (fetch (LEAFDEVICE PFSOSTYPE) of DEVICE))
           FIELDS HOST REMOTENAME DEV DIR NAME EXT VERSION VALUE QUOTEP)
          (SETQ FIELDS (UNPACKFILENAME.STRING FILENAME NIL NIL OSTYPE))
          (SETQ QUOTEP (STRPOS "'" FILENAME))
          (for TAIL on FIELDS by (CDDR TAIL)
             do (SETQ VALUE (CADR TAIL))
                   (if (AND QUOTEP (STRPOS "'" VALUE))
                       then 

                             (* ;; "Remove quotes.  This is a hack to let people quote funny chars somehow.  It's pretty limited, since we don't know how to quote them coming back.")

                             (SETQ VALUE (\LEAF.STRIP.QUOTES VALUE)))
                   (SELECTQ (CAR TAIL)
                       (HOST [SETQ HOST (OR (\CANONICAL.HOSTNAME VALUE)
                                            (RETURN (AND (NOT NOERROR)
                                                         (ERROR "Host not found" HOST])
                       (DEVICE (SETQ DEV VALUE))
                       (DIRECTORY (SETQ DIR VALUE))
                       (NAME (SETQ NAME VALUE))
                       (EXTENSION (SETQ EXT VALUE))
                       (VERSION (SETQ VERSION VALUE))
                       NIL))
          [if (NULL HOST)
              then (RETURN (AND (NEQ NOERROR T)
                                    (LISPERROR "BAD FILE NAME" FILENAME]
          (COND
             ((SETQ HOST (\CANONICAL.HOSTNAME HOST)))
             (NOERROR (RETURN NIL))
             (T (ERROR "Host not found" HOST)))

     (* ;; "Convert name to native syntax")

          (RETURN (CONS HOST (CONCATLIST (NCONC (AND DEV (LIST DEV))
                                                (AND DIR (SELECTQ OSTYPE
                                                             (UNIX (LIST "/" DIR "/"))
                                                             (VMS (LIST "[" DIR "]"))
                                                             (LIST "<" DIR ">")))
                                                (LIST NAME)
                                                (if (AND EXT (NEQ 0 (NCHARS EXT)))
                                                    then (LIST "." EXT)
                                                  else (SELECTQ OSTYPE
                                                               ((TENEX TOPS20 VMS) 
                                                             (* ; 
                                                           "even extensionless files have a dot")
                                                                    (LIST "."))
                                                               NIL))
                                                (AND VERSION (NEQ 0 (NCHARS VERSION))
                                                     (LIST (SELECTQ OSTYPE
                                                               (TOPS20 ".")
                                                               ((IFS UNIX) 
                                                             (* ; "Unix? you ask.  Well, the Leaf server doesn't seem to understand semicolon, even though that's how the files are stored!")
                                                                    "!")
                                                               ";")
                                                           VERSION])

(\LEAF.STRIP.QUOTES
  [LAMBDA (NAME)                                         (* ; "Edited 11-Jan-88 16:13 by bvm")

    (* ;; "Remove quotes from file NAME, since remote devices never understand our quoting convention (actually, there isn't one in the Leaf protocol).  Currently, we only remove quotes that look like they're quoting something interesting.")

    (CONCATCODES (for (TAIL _ (CHCON NAME)) by (CDR TAIL) while TAIL
                    collect (if (AND (EQ (CAR TAIL)
                                                 (CHARCODE "'"))
                                             (CDR TAIL))
                                    then                 (* ; "skip quote")
                                          (SETQ TAIL (CDR TAIL)))
                          (CAR TAIL])

(\LEAF.GETFILEDATES
  [LAMBDA (STREAM FLG)                                   (* ; "Edited 24-May-91 15:07 by jds")
    (PROG ((INFOBLK (fetch (LEAFSTREAM LEAFINFO) of STREAM))
           START)
          (COND
             [(NOT INFOBLK)
              (replace (LEAFSTREAM LEAFINFO) of STREAM with (SETQ INFOBLK (create
                                                                                       LEAFINFOBLOCK]
             ((NOT FLG)
              (RETURN INFOBLK)))
          [COND
             ((SETQ START (\LEAF.READFILEPROP STREAM 0 (UNFOLD 3 BYTESPERCELL)))
                                                             (* ; 
                                                           "Get 3 info dates from IFS leader")
              (\BLT INFOBLK (CDR START)
                    (UNFOLD 3 WORDSPERCELL))
              (RELEASE.PUP (CAR START)))
             (T                                              (* ; "Can't read leader page dates")
                (\CLEARBYTES INFOBLK 0 (UNFOLD 3 BYTESPERCELL]
          (\LEAF.SETVALIDATION STREAM)
          (RETURN INFOBLK])

(\LEAF.GETFILEINFO
  [LAMBDA (STREAM ATTRIBUTE DEV)              (* ; 
                                                "Edited  2-Nov-92 03:36 by sybalsky:mv:envos")
    (COND
       ((type? STREAM STREAM)                            (* ; "Handle open case easily")
        (\LEAF.GETFILEINFO.OPEN STREAM ATTRIBUTE))
       (T (PROG (DEVINFO SEQUIN RESULT)
                [COND
                   ((FMEMB ATTRIBUTE '(CREATIONDATE ICREATIONDATE))

                    (* ;; "Use the LOOKUPFILE protocol.  Would like to have LENGTH here, too, but might disagree with Leaf due to race conditions;  e.g.  LENGTH of a file that I just had closed could get an old length")

                    (COND
                       ((AND [SETQ SEQUIN (fetch (PUPFILESERVER PFSLEAFSEQUIN)
                                             of (SETQ DEVINFO (fetch DEVICEINFO of DEV]
                             (SETQ RESULT (fetch (SEQUIN LEAFCACHEDFILE) of SEQUIN))
                             (EQ (fetch (STREAM FULLFILENAME) of RESULT)
                                 STREAM))                    (* ; "A name we know about")
                        (RETURN (\LEAF.GETFILEINFO.OPEN RESULT ATTRIBUTE)))
                       ((NEQ (SETQ RESULT (\IFS.LOOKUPFILE STREAM 'OLD ATTRIBUTE DEVINFO))
                             '?)
                        (RETURN RESULT]

           (* ;; "To get attributes, have to open file, read them, then close.")

                (RETURN (COND
                           ((SETQ STREAM (\LEAF.GETFILE DEV STREAM 'NONE 'OLD))
                            (PROG1 (\LEAF.GETFILEINFO.OPEN STREAM ATTRIBUTE)
                                   (\LEAF.CLOSEFILE STREAM T])

(\LEAF.GETFILEINFO.OPEN
  [LAMBDA (STREAM ATTRIBUTE)                  (* ; 
                                                "Edited  2-Nov-92 03:36 by sybalsky:mv:envos")
    (SELECTQ ATTRIBUTE
        (LENGTH (create BYTEPTR
                       PAGE _ (fetch (STREAM EPAGE) of STREAM)
                       OFFSET _ (fetch (STREAM EOFFSET) of STREAM)))
        (CREATIONDATE (GDATE (\LEAF.GETFILEINFO.OPEN STREAM 'ICREATIONDATE)))
        (WRITEDATE (GDATE (\LEAF.GETFILEINFO.OPEN STREAM 'IWRITEDATE)))
        (READDATE (GDATE (\LEAF.GETFILEINFO.OPEN STREAM 'IREADDATE)))
        (ICREATIONDATE (ALTO.TO.LISP.DATE (fetch (LEAFINFOBLOCK LFCREATIONDATE)
                                             of (\LEAF.GETFILEDATES STREAM))))
        (IWRITEDATE (ALTO.TO.LISP.DATE (fetch (LEAFINFOBLOCK LFWRITEDATE) of (
                                                                                 \LEAF.GETFILEDATES
                                                                                      STREAM))))
        (IREADDATE (ALTO.TO.LISP.DATE (fetch (LEAFINFOBLOCK LFREADDATE) of (
                                                                                 \LEAF.GETFILEDATES
                                                                                    STREAM))))
        ((TYPE BYTESIZE) 
             [PROG (FT (BYTESIZE 10Q))
                   [SETQ FT (COND
                               [(SETQ FT (\LEAF.READFILEPROP STREAM \OFFSET.FILETYPE 
                                                \LEN.FILETYPE&SIZE))
                                                             (* ; "FT = (pup  . base)")
                                (PROG1 (SELECTC (\GETBASE (CDR FT)
                                                       0)
                                           (\FT.UNKNOWN NIL)
                                           (\FT.TEXT 'TEXT)
                                           (\FT.BINARY (SETQ BYTESIZE (\GETBASE (CDR FT)
                                                                             1))
                                                       'BINARY)
                                           '?)
                                    (RELEASE.PUP (CAR FT)))]
                               (T '?]
                   (RETURN (COND
                              ((EQ ATTRIBUTE 'BYTESIZE)
                               BYTESIZE)
                              (T FT])
        (AUTHOR [LET ((BASE (\LEAF.READFILEPROP STREAM \OFFSET.AUTHOR \LEN.AUTHOR)))
                     (AND BASE (PROG1 (GetBcplString (CDR BASE))
                                   (RELEASE.PUP (CAR BASE)))])
        ((BACKUPDATE IBACKUPDATE) 
             [LET ((BASE (\LEAF.READFILEPROP STREAM \OFFSET.BACKUPDATE \LEN.DATE))
                   DT)
                  (COND
                     (BASE (SETQ DT (fetch (LEAFINFOBLOCK LFCREATIONDATE) of (CDR BASE)))
                           (RELEASE.PUP (CAR BASE))
                           (if (NEQ DT 0)
                               then                      (* ; "Zero means it hasn't been")
                                     (SETQ DT (ALTO.TO.LISP.DATE DT))
                                     (if (EQ ATTRIBUTE 'IBACKUPDATE)
                                         then DT
                                       else (GDATE DT])
        NIL])

(\LEAF.GETFILENAME
  [LAMBDA (NAME RECOG DEV)                    (* ; 
                                                "Edited  2-Nov-92 03:36 by sybalsky:mv:envos")
    (PROG ((DEVINFO (fetch DEVICEINFO of DEV))
           SEQUIN RESULT)
          (RETURN (OR [COND
                         ((AND (SETQ SEQUIN (fetch (PUPFILESERVER PFSLEAFSEQUIN) of DEVINFO))
                               (SETQ RESULT (fetch (SEQUIN LEAFCACHEDFILE) of SEQUIN))
                               (EQ (fetch (STREAM FULLFILENAME) of RESULT)
                                   NAME))                    (* ; "A name we know about")
                          NAME)
                         ((AND (NEQ RECOG 'NEW)
                               (NEQ (SETQ RESULT (\IFS.LOOKUPFILE NAME RECOG 'NAME DEVINFO))
                                    '?))
                          RESULT)
                         (T (\LEAF.GETFILE DEV NAME 'NONE RECOG T 'NAME]
                      (SELECTQ RECOG
                          ((NEW OLD/NEW) 
                               (\GENERIC.OUTFILEP NAME DEV))
                          NIL])

(\LEAF.OPENFILE
  [LAMBDA (FILENAME ACCESS RECOG OTHERINFO DEV)
                                                  (* ; 
                                                "Edited  2-Nov-92 03:36 by sybalsky:mv:envos")
    (PROG ((DEVINFO (fetch DEVICEINFO of DEV))
           STREAM TYPE BYTESIZE OLDHANDLE CRDATE PROPS SEQUIN EOL)
          [COND
             ((type? STREAM FILENAME)                    (* ; 
                                                           "Hmm?  trying to reopen, perhaps?")
              (COND
                 ((fetch (STREAM ACCESS) of FILENAME)
                  (RETURN (LISPERROR "FILE WON'T OPEN" FILENAME)))
                 (T (SETQ FILENAME (fetch (STREAM FULLFILENAME) of (SETQ OLDHANDLE FILENAME]
          (for X in OTHERINFO
             do                                          (* ; 
                                                           "Check device-dependent parameters")
                   (SELECTQ [CAR (OR (LISTP X)
                                     (SETQ X (LIST X T]
                       ((TYPE FILETYPE)                      (* ; 
                                                           "Set the file TYPE (TEXT or BINARY)")
                            (SETQ TYPE (CDR X)))
                       (BYTESIZE (SETQ BYTESIZE (OR (FIXP (CADR X))
                                                    (\ILLEGAL.ARG X))))
                       (CREATIONDATE (SETQ CRDATE (IDATE (CADR X))))
                       (ICREATIONDATE (SETQ CRDATE (OR (FIXP (CADR X))
                                                       (\ILLEGAL.ARG X))))
                       (DON'T.CHANGE.DATE 

                                 (* ;; "Don't change create date.  In order to do this, we have to look at the current date of the file, save it, then rewrite when we open the file for real")

                            (COND
                               ((AND (NEQ ACCESS 'INPUT)
                                     (SETQ OLDHANDLE (\LEAF.GETFILE DEV FILENAME 'NONE
                                                            'OLD T 'DATES OLDHANDLE)))
                                (SETQ FILENAME (fetch (STREAM FULLFILENAME) of OLDHANDLE))
                                (SETQ CRDATE (\LEAF.CREATIONDATE OLDHANDLE))
                                (\LEAF.CLOSEFILE OLDHANDLE NIL NIL T))))
                       (SEQUENTIAL                           (* ; "Hook for FTP")
                                   (COND
                                      ((AND (CADR X)
                                            \FTPAVAILABLE
                                            (OR (NEQ (fetch (PUPFILESERVER PFSOSTYPE)
                                                        of DEVINFO)
                                                     'UNIX)
                                                UNIXFTPFLG)
                                            (SETQ STREAM (\FTP.OPENFILE FILENAME ACCESS RECOG 
                                                                OTHERINFO)))
                                       (RETURN))))
                       (EOL (SETQ EOL (SELECTQ (CADR X)
                                          (CR CR.EOLC)
                                          (LF LF.EOLC)
                                          (CRLF CRLF.EOLC)
                                          (\ILLEGAL.ARG X))))
                       (push PROPS X)))
          [COND
             (STREAM)
             ((SETQ STREAM (\LEAF.GETFILE DEV FILENAME ACCESS RECOG 'FIND NIL OLDHANDLE T))
                                                             (* ; "Returns NIL if file not found")
              (COND
                 (CRDATE (\LEAF.SETCREATIONDATE STREAM CRDATE))
                 (T (\LEAF.GETFILEDATES STREAM)))
              (COND
                 ([AND (NEQ ACCESS 'INPUT)
                       (COND
                          (TYPE                              (* ; "Type NIL overrides default")
                                (SETQ TYPE (CAR TYPE)))
                          (T (AND (SETQ TYPE DEFAULTFILETYPE)
                                  (EQ (fetch (STREAM EPAGE) of STREAM)
                                      0)
                                  (EQ (fetch (STREAM EOFFSET) of STREAM)
                                      0]

                  (* ;; "Set file type if explicitly requested, or if this is a new output file and there is a global default")

                  (\LEAF.SETFILETYPE STREAM TYPE BYTESIZE)))
              (SETQ SEQUIN (fetch (LEAFSTREAM LEAFCONNECTION) of STREAM))
              (COND
                 ((IGREATERP (fetch (SEQUIN LEAFCACHEHITS) of SEQUIN)
                         77777Q)                             (* ; "Keep counters from overflowing")
                  (replace (SEQUIN LEAFCACHEHITS) of SEQUIN with 0)
                  (replace (SEQUIN LEAFCACHEMISSES) of SEQUIN with 0)))
              (COND
                 ((IGREATERP (fetch (SEQUIN %#SEQTIMEOUTS) of SEQUIN)
                         77777Q)
                  (replace (SEQUIN %#SEQRESTARTS) of SEQUIN with 0)
                  (replace (SEQUIN %#SEQTIMEOUTS) of SEQUIN with 0)
                  (replace (SEQUIN %#SEQDUPLICATES) of SEQUIN with 0)))
              (replace (STREAM CBUFSIZE) of STREAM with 0)
                                                             (* ; 
                                                      "For the benefit of uCode and PageMapped fns")
              (replace (STREAM CBUFPTR) of STREAM with NIL)
              (replace (STREAM EOLCONVENTION) of STREAM
                 with (OR EOL (SELECTQ (fetch (PUPFILESERVER PFSOSTYPE) of DEVINFO)
                                      ((TENEX TOPS20) 
                                           CRLF.EOLC)
                                      (UNIX LF.EOLC)
                                      CR.EOLC]
          (RETURN STREAM])

(\LEAF.READFILENAME
  [LAMBDA (STREAM DEVINFO)                               (* ; "Edited 24-May-91 15:11 by jds")
    (LET ([REMOTENAME (LET ((NAMEBASE (\LEAF.READFILEPROP STREAM \OFFSET.FILENAME 
                                             \MAXLEN.FILENAME)))
                                                             (* ; "Returns (pup . base)")
                           (AND NAMEBASE (PROG1 (GetBcplString (CDR NAMEBASE))
                                             (RELEASE.PUP (CAR NAMEBASE)))]
          (OSTYPE (fetch (PUPFILESERVER PFSOSTYPE) of DEVINFO)))
         (COND
            ((NOT REMOTENAME)                                (* ; 
                                                           "Some hosts may refuse us the name")
             NIL)
            (T [SETQ REMOTENAME (CL:APPLY (FUNCTION PACKFILENAME.STRING)
                                       'HOST
                                       (fetch (SEQUIN SEQNAME) of (fetch (LEAFSTREAM
                                                                                      LEAFCONNECTION)
                                                                             of STREAM))
                                       (UNPACKFILENAME.STRING (\LEAF.ADD.QUOTES REMOTENAME
                                                                     'IFS)
                                              NIL NIL (if (EQ OSTYPE 'UNIX)
                                                          then 
                                                             (* ; 
                     "Kludge: call it an IFS, since current Unix servers return ! for the version.")
                                                                'IFS
                                                        else OSTYPE]
               (if *UPPER-CASE-FILE-NAMES*
                   then (MKATOM (U-CASE REMOTENAME))
                 else REMOTENAME])

(\LEAF.ADD.QUOTES
  [LAMBDA (NAME OSTYPE)                                  (* ; "Edited 11-Jan-88 16:32 by bvm")

    (* ;; "The only funny char we know about is quote, so quote all the quotes with a quote.")

    (bind (N _ 1)
           I PIECES while (SETQ I (STRPOS "'" NAME N)) do (push PIECES "'"
                                                                         (SUBSTRING NAME N I))
                                                                 (SETQ N (ADD1 I))
       finally (if (AND (EQ OSTYPE 'IFS)
                                (SETQ I (STRPOS ".!" NAME N)))
                       then                              (* ; "Yet another piece of nonsense: for IFS file ending in dot, we'd better quote the dot, lest it be discarded")
                             (push PIECES "'" (SUBSTRING NAME N (SUB1 I)))
                             (SETQ N I))
             (RETURN (if PIECES
                         then (if (<= N (NCHARS NAME))
                                      then (push PIECES (SUBSTRING NAME N)))
                               (CONCATLIST (DREVERSE PIECES))
                       else                              (* ; "nothing got quoted")
                             NAME])

(\LEAF.READFILEPROP
  [LAMBDA (STREAM OFFSET LEN)                            (* ; "Edited 24-May-91 15:07 by jds")

    (* ;; "Read a chunk of the IFS leader page starting at OFFSET for LEN bytes.  Returns a dotted pair, car of which is the reply pup and CDR is a pointer inside it to the desired data")

    (PROG ((CONNECTION (fetch (LEAFSTREAM LEAFCONNECTION) of STREAM))
           (OPUP (ALLOCATE.PUP))
           DATA IPUP)
          (SETQ DATA (fetch PUPCONTENTS of OPUP))
          (replace (LEAFDATA OPWORD) of DATA with (LLSH \LEAFOP.READ \OPCODE.SHIFT))
          (replace (LEAFDATA HANDLE) of DATA with (fetch (LEAFSTREAM LEAFHANDLE)
                                                                 of STREAM))
          (replace (LEAFDATA FILEADDRESS) of DATA with (IDIFFERENCE OFFSET 
                                                                          \BYTES.PER.TRIDENT.PAGE))
          (replace (LEAFDATA SIGNEXTEND) of DATA with 0)
          (replace (LEAFDATA DATALENGTH) of DATA with LEN)
          (replace (LEAFDATA LEAFLENGTH) of DATA with \LEN.FILEREQUEST)
          (SETQ IPUP (\SENDLEAF CONNECTION OPUP STREAM NOFILEPROPERROR))
          (RETURN (COND
                     ((EQ (fetch (LEAFPACKET LEAFSTATUS) of IPUP)
                          \LEAF.GOODSTATUS)
                      (CONS IPUP (\ADDBASE (fetch PUPCONTENTS of IPUP)
                                        (FOLDLO \LEN.READANSWER BYTESPERWORD])

(\LEAF.READPAGES
  [LAMBDA (STREAM FIRSTPAGE BUFFERLIST)       (* ; 
                                                "Edited  2-Nov-92 03:36 by sybalsky:mv:envos")
    (for BUF inside BUFFERLIST as PAGE# from FIRSTPAGE bind LEN
       sum [COND
                  ((.PAGE.IS.AFTER.EOF. STREAM PAGE#)        (* ; "after end of file")
                   (SETQ LEN 0))
                  (T (PROG (OPUP IPUP DATA)
                       RETRY
                           (SETQ OPUP (\LEAF.REQUESTPAGE STREAM PAGE# T))
                           (for NEWPAGE# from (ADD1 PAGE#) as I
                              to (fetch (LEAFSTREAM LEAFCACHECNT) of STREAM)
                              until (.PAGE.IS.AFTER.EOF. STREAM NEWPAGE#)
                              do                         (* ; 
                                                "Ask for pages immediately following this one, too")
                                    (\LEAF.REQUESTPAGE STREAM NEWPAGE#))
                           (until (NEQ (SETQ IPUP (fetch EPUSERFIELD of OPUP))
                                           STREAM)
                              do (AWAIT.EVENT [fetch (SEQUIN SEQEVENT)
                                                     of (OR (fetch (LEAFSTREAM LEAFCONNECTION
                                                                                  ) of STREAM)
                                                                (LISPERROR "FILE NOT OPEN"
                                                                       (fetch (STREAM 
                                                                                         FULLFILENAME
                                                                                         )
                                                                          of STREAM]
                                            \ETHERTIMEOUT))
                           (RELEASE.PUP OPUP)
                           (COND
                              ((AND (NEQ IPUP \LEAF.BROKEN.STATUS)
                                    (NEQ (fetch (LEAFDATA LEAFOPCODE)
                                            of (SETQ DATA (fetch PUPCONTENTS of IPUP)))
                                         \LEAFOP.ERROR))
                               (SETQ LEN (- (fetch (LEAFDATA LEAFLENGTH) of DATA)
                                            \LEN.READANSWER))
                               (\BLT BUF (\ADDBASE DATA (FOLDLO \LEN.READANSWER BYTESPERWORD))
                                     (FOLDHI LEN BYTESPERWORD))
                               (RELEASE.PUP IPUP)
                               (RETURN LEN))
                              ((NOT (READABLE STREAM))
                               (LISPERROR "FILE NOT OPEN" (fetch (STREAM FULLFILENAME)
                                                             of STREAM)))
                              ((NEQ IPUP \LEAF.BROKEN.STATUS)
                               (\LEAF.ERROR IPUP (fetch (STREAM FULLFILENAME) of STREAM)
                                      (fetch (LEAFSTREAM LEAFCONNECTION) of STREAM)
                                      OPUP))
                              (T (HELP "Failed to read page of file" (fetch (STREAM FULLFILENAME)
                                                                        of STREAM))
                                 (GO RETRY]
             [COND
                ((< LEN BYTESPERPAGE)
                 (\CLEARBYTES BUF LEN (- BYTESPERPAGE LEN]
             LEN])

(\LEAF.REQUESTPAGE
  [LAMBDA (STREAM PAGE# IMMEDIATE)                       (* ; "Edited 24-May-91 15:07 by jds")

    (* ;; "Requests PAGE# of STREAM, possibly finding it in the cache first.  If IMMEDIATE is true, then we want the page now, and it should be removed from the cache and returned;  otherwise it is completely optional whether we ask for the page at all or what we return")

    (PROG ((CACHE (\LEAF.LOOKUPCACHE STREAM PAGE# IMMEDIATE))
           OPUP DATA)
          [COND
             ((CDR CACHE)                                    (* ; "Cache hit!")
              [COND
                 (IMMEDIATE (INCLEAFSTAT (fetch (SEQUIN LEAFCACHEHITS) of (fetch
                                                                                   (LEAFSTREAM 
                                                                                       LEAFCONNECTION
                                                                                          )
                                                                                     of STREAM)))
                        (COND
                           ((ILESSP (fetch (LEAFSTREAM LEAFCACHECNT) of STREAM)
                                   \LEAF.MAXLOOKAHEAD)       (* ; 
                                                           "Reward STREAM for being sequential")
                            (add (fetch (LEAFSTREAM LEAFCACHECNT) of STREAM)
                                   1]
              (RETURN (CDR CACHE]
          [COND
             (IMMEDIATE                                      (* ; 
                             "Cache miss, so we probably aren't very sequential;  be more cautious")
                    (replace (LEAFSTREAM LEAFCACHECNT) of STREAM with 1)
                    (INCLEAFSTAT (fetch (SEQUIN LEAFCACHEMISSES) of (fetch (LEAFSTREAM
                                                                                        
                                                                                       LEAFCONNECTION
                                                                                        )
                                                                               of STREAM]
          [SETQ DATA (fetch PUPCONTENTS of (SETQ OPUP (ALLOCATE.PUP]
          (replace (LEAFDATA OPWORD) of DATA with (LLSH \LEAFOP.READ \OPCODE.SHIFT))
          (replace (LEAFDATA HANDLE) of DATA with (fetch (LEAFSTREAM LEAFHANDLE)
                                                                 of STREAM))
          (replace (LEAFDATA FILEADDRESS) of DATA
             with (create BYTEPTR
                             PAGE _ PAGE#
                             OFFSET _ 0))
          (replace (LEAFDATA READWRITEMODE) of DATA with \LEAFMODE.DONTEXTEND)
                                                             (* ; 
                              "i.e.  don't attempt to read past EOF, in case this is the last page")
          (replace (LEAFDATA DATALENGTH) of DATA with BYTESPERPAGE)
          (replace (LEAFDATA LEAFLENGTH) of DATA with \LEN.FILEREQUEST)
          (RETURN (COND
                     ((\SENDLEAF (fetch (LEAFSTREAM LEAFCONNECTION) of STREAM)
                             OPUP STREAM T 'GO (NOT IMMEDIATE))
                      (AND CACHE (RPLACD CACHE OPUP))
                      OPUP])

(\LEAF.LOOKUPCACHE
  [LAMBDA (STREAM PAGE# DELETE)                          (* ; "Edited 24-May-91 15:07 by jds")

    (* ;; "Looks up PAGE# in STREAM's cache.  If it finds an entry, it returns it and, if DELETE is true, deletes it from the cache;  otherwise if DELETE is NIL, it inserts a new empty entry for PAGE#")

    (for I from 0 bind (CACHE _ (fetch (LEAFSTREAM LEAFPAGECACHE) of STREAM))
                                PREV while CACHE do [COND
                                                               ((IEQP (CAAR CACHE)
                                                                      PAGE#)
                                                                [COND
                                                                   ((NOT DELETE)
                                                             (* ; "Don't remove entry from cache")
                                                                    )
                                                                   (PREV (RPLACD PREV (CDR CACHE)))
                                                                   (T (replace (LEAFSTREAM 
                                                                                        LEAFPAGECACHE
                                                                                          )
                                                                         of STREAM
                                                                         with (CDR CACHE]
                                                                (RETURN (CAR CACHE]
                                                           (SETQ CACHE (CDR (SETQ PREV CACHE)))
       finally [COND
                      ((NOT DELETE)
                       (SETQ CACHE (LIST (CONS PAGE# NIL)))
                       (COND
                          [PREV (RPLACD PREV CACHE)
                                (COND
                                   ((IGREATERP I \LEAF.MAXCACHE)
                                                             (* ; "Throw out old cache entries")
                                    (replace (LEAFSTREAM LEAFPAGECACHE) of STREAM
                                       with (CDR (fetch (LEAFSTREAM LEAFPAGECACHE)
                                                        of STREAM]
                          (T (replace (LEAFSTREAM LEAFPAGECACHE) of STREAM with CACHE]
             (RETURN (CAR CACHE])

(CLEAR.LEAF.CACHE
  [LAMBDA (HOST)                                         (* ; "Edited 24-May-91 15:11 by jds")
    (COND
       (HOST (PROG ([DEVICE (OR (\GETDEVICEFROMNAME HOST T T)
                                (AND (SETQ HOST (\CANONICAL.HOSTNAME HOST))
                                     (\GETDEVICEFROMNAME HOST T T]
                    CONNECTION DEVINFO)
                   (RETURN (COND
                              ((AND DEVICE (type? PUPFILESERVER (SETQ DEVINFO
                                                                     (fetch DEVICEINFO
                                                                        of DEVICE)))
                                    (SETQ CONNECTION (ffetch (PUPFILESERVER PFSLEAFSEQUIN)
                                                        of DEVINFO))
                                    (fetch (SEQUIN LEAFCACHEDFILE) of CONNECTION))
                               (\LEAF.FLUSH.CACHE CONNECTION])

(LEAF.ASSURE.FINISHED
  [LAMBDA (STREAM)                            (* ; 
                                                "Edited  2-Nov-92 03:36 by sybalsky:mv:envos")
    (PROG [(SEQUIN (fetch (LEAFSTREAM LEAFCONNECTION) of (SETQ STREAM (\DTEST STREAM
                                                                                     'STREAM]
      TOP [COND
             ((type? SEQUIN SEQUIN)
              (WITH.MONITOR (fetch (SEQUIN SEQLOCK) of SEQUIN)
                  (bind PUP
                     until [AND [OR [NOT (SETQ PUP (fetch SYSQUEUEHEAD
                                                          of (fetch (SEQUIN SEQDONEQ)
                                                                    of SEQUIN]
                                        (while PUP
                                           never (PROG1 (EQ (fetch EPUSERFIELD of PUP)
                                                                STREAM)
                                                         (SETQ PUP (fetch EPLINK of PUP)))]
                                    (OR [NOT (SETQ PUP (fetch SYSQUEUEHEAD
                                                          of (fetch (SEQUIN SEQRETRANSMITQ)
                                                                    of SEQUIN]
                                        (while PUP
                                           never (PROG1 (EQ (fetch EPUSERFIELD of PUP)
                                                                STREAM)
                                                         (SETQ PUP (fetch EPLINK of PUP)))]
                     do                                  (* ; 
                          "Not quite right, because it doesn't catch stuff in the retransmit queue")
                           (MONITOR.AWAIT.EVENT (fetch (SEQUIN SEQLOCK) of SEQUIN)
                                  (fetch (SEQUIN SEQEVENT) of SEQUIN)
                                  \ETHERTIMEOUT)))
              (COND
                 ((NEQ (fetch (LEAFSTREAM LEAFERRORCNT) of STREAM)
                       0)
                  (ERROR "Waiting for operation on broken file to finish" (fetch (STREAM 
                                                                                         FULLFILENAME
                                                                                            )
                                                                             of STREAM))
                  (GO TOP]
          (RETURN T])

(\LEAF.FORCEOUTPUT
  [LAMBDA (STREAM)                                       (* bvm%: "11-Jul-84 11:31")
    (\PAGED.FORCEOUTPUT STREAM)
    (LEAF.ASSURE.FINISHED STREAM])

(\LEAF.FLUSH.CACHE
  [LAMBDA (SEQUIN)                                       (* ; "Edited 24-May-91 15:07 by jds")
    (WITH.MONITOR (fetch (SEQUIN LEAFOPENCLOSELOCK) of SEQUIN)
        [LET ((CACHE (fetch (SEQUIN LEAFCACHEDFILE) of SEQUIN)))
             (COND
                ((NULL CACHE)
                 NIL)
                ((fetch (LEAFSTREAM LEAFREALLYOPEN) of CACHE)
                 (replace (SEQUIN LEAFCACHEDFILE) of SEQUIN with NIL)
                 NIL)
                (T (\LEAF.CLOSEFILE CACHE SEQUIN NIL :CACHE)
                   (fetch (SEQUIN SEQNAME) of SEQUIN])])

(\LEAF.RENAMEFILE
  [LAMBDA (OLD-DEVICE OLDFILE NEW-DEVICE NEWFILE)        (* hdj " 8-May-86 15:20")
    (OR (AND \FTPAVAILABLE (OR (NEQ (GETHOSTINFO (fetch (FDEV DEVICENAME) of OLD-DEVICE)
                                           'OSTYPE)
                                    'UNIX)
                               UNIXFTPFLG)
             (\FTP.RENAMEFILE OLD-DEVICE OLDFILE NEW-DEVICE NEWFILE))
        (\GENERIC.RENAMEFILE OLD-DEVICE OLDFILE NEW-DEVICE NEWFILE])

(\LEAF.REOPENFILE
  [LAMBDA (NAME ACCESS RECOG OTHERINFO FDEV STREAM)
                                                  (* ; 
                                                "Edited  2-Nov-92 03:36 by sybalsky:mv:envos")

(* ;;; "Called after, say, a LOGOUT to restore the file to its old state.  We reopen the file and return a new file handle")

    (PROG (NEWSTREAM OLDINFO NEWINFO OLDDATES)
          [COND
             ((NEQ ACCESS 'INPUT)

              (* ;; "Problem: when we reopen the file for write, we change the write and creation dates, so our caller thinks the file has been modified.  So first open the file for read and look at the dates, and if they're the same as the old filehandle's, prepare to restore them")

              (COND
                 ((SETQ NEWSTREAM (\LEAF.GETFILE FDEV NAME 'NONE 'OLD T 'DATES))
                  [COND
                     ((AND [IEQP (fetch (LEAFINFOBLOCK LFCREATIONDATE)
                                    of (SETQ OLDINFO (fetch (LEAFSTREAM LEAFINFO)
                                                            of STREAM)))
                                 (fetch (LEAFINFOBLOCK LFCREATIONDATE)
                                    of (SETQ NEWINFO (fetch (LEAFSTREAM LEAFINFO)
                                                            of NEWSTREAM]
                           (IEQP (fetch (LEAFINFOBLOCK LFWRITEDATE) of OLDINFO)
                                 (fetch (LEAFINFOBLOCK LFWRITEDATE) of NEWINFO)))
                                                             (* ; 
                                                     "Creation and write dates are indeed the same")
                      (SETQ OLDDATES (\LEAF.CREATIONDATE NEWSTREAM]
                  (\LEAF.CLOSEFILE NEWSTREAM NIL NIL T))
                 (T                                          (* ; 
                                                  "If we can't even find the file, there's no hope")
                    (RETURN NIL]
          [COND
             ((AND (SETQ NEWSTREAM (\LEAF.GETFILE FDEV NAME ACCESS RECOG T NIL NEWSTREAM))
                   OLDDATES)                                 (* ; 
                                                           "Change the filedates to the old dates")
              (\LEAF.SETCREATIONDATE NEWSTREAM OLDDATES)

              (* ;; "And smash the validation of the old handle to be the new validation.  This is sort of a cheat, but it works to fool \REVALIDATEFILE")

              (replace (STREAM VALIDATION) of STREAM with (fetch (STREAM VALIDATION)
                                                                         of NEWSTREAM]
          (RETURN NEWSTREAM])

(\LEAF.CREATIONDATE
  [LAMBDA (STREAM)                                       (* ; "Edited 24-May-91 15:08 by jds")
    (ALTO.TO.LISP.DATE (fetch (LEAFINFOBLOCK LFCREATIONDATE) of (fetch (LEAFSTREAM 
                                                                                          LEAFINFO)
                                                                           of STREAM])

(\LEAF.SETCREATIONDATE
  [LAMBDA (STREAM DATE)                                  (* ; "Edited 24-May-91 15:08 by jds")
                                                             (* ; 
                                                           "DATE is integer in Lisp date format")
    (PROG ((INFOBLK (\LEAF.GETFILEDATES STREAM))
           (FILEDATE (LISP.TO.ALTO.DATE DATE))
           (OPUP (ALLOCATE.PUP))
           DATA)
          (SETQ DATA (fetch PUPCONTENTS of OPUP))
          (replace (LEAFDATA OPWORD) of DATA with (LLSH \LEAFOP.WRITE \OPCODE.SHIFT))
          (replace (LEAFDATA HANDLE) of DATA with (fetch (LEAFSTREAM LEAFHANDLE)
                                                                 of STREAM))
          (replace (LEAFDATA FILEADDRESS) of DATA with (IDIFFERENCE 0 
                                                                          \BYTES.PER.TRIDENT.PAGE))
                                                             (* ; 
                                                           "negative address into leader page")
          (replace (LEAFDATA SIGNEXTEND) of DATA with 0)
          (replace (LEAFDATA DATALENGTH) of DATA with \LEN.DATE)
          (replace (LEAFDATA LEAFFILEDATE) of DATA with FILEDATE)
          (replace (LEAFDATA LEAFLENGTH) of DATA with (IPLUS \LEN.FILEREQUEST \LEN.DATE))
          (\SENDLEAF (fetch (LEAFSTREAM LEAFCONNECTION) of STREAM)
                 OPUP STREAM NIL T)
          (replace (LEAFINFOBLOCK LFCREATIONDATE) of INFOBLK with FILEDATE)
          (\LEAF.SETVALIDATION STREAM)                   (* ; 
                                                           "Since validation depends on file dates")
          (RETURN T])

(\LEAF.SETFILEINFO
  [LAMBDA (STREAM ATTRIBUTE VALUE DEV)                   (* bvm%: "12-SEP-83 14:16")
    (PROG ((WASOPEN (type? STREAM STREAM)))
          (SELECTQ ATTRIBUTE
              (CREATIONDATE (SETQ VALUE (OR (IDATE VALUE)
                                            (LISPERROR "ILLEGAL ARG" VALUE))))
              (ICREATIONDATE (OR (FIXP VALUE)
                                 (LISPERROR "NON-NUMERIC ARG" VALUE)))
              (TYPE)
              (RETURN))
          (RETURN (COND
                     ([OR WASOPEN (SETQ STREAM (\LEAF.GETFILE DEV STREAM 'NONE 'OLD]
                      (PROG1 (SELECTQ ATTRIBUTE
                                 (TYPE (\LEAF.SETFILETYPE STREAM VALUE))
                                 (\LEAF.SETCREATIONDATE STREAM VALUE))
                          (COND
                             ((NOT WASOPEN)
                              (\LEAF.CLOSEFILE STREAM T))))])

(\LEAF.SETFILETYPE
  [LAMBDA (STREAM TYPE BYTESIZE)                         (* ; "Edited 24-May-91 15:08 by jds")
                                                             (* ; 
                                                           "Sets 'type' of file to TEXT or BINARY")
    (PROG ((OPUP (ALLOCATE.PUP))
           DATA)
          (SETQ DATA (fetch PUPCONTENTS of OPUP))
          (replace (LEAFDATA OPWORD) of DATA with (LLSH \LEAFOP.WRITE \OPCODE.SHIFT))
          (replace (LEAFDATA HANDLE) of DATA with (fetch (LEAFSTREAM LEAFHANDLE)
                                                                 of STREAM))
          (replace (LEAFDATA FILEADDRESS) of DATA with (IDIFFERENCE \OFFSET.FILETYPE 
                                                                          \BYTES.PER.TRIDENT.PAGE))
                                                             (* ; 
                                                           "negative address into leader page")
          (replace (LEAFDATA SIGNEXTEND) of DATA with 0)
          (replace (LEAFDATA DATALENGTH) of DATA with \LEN.FILETYPE&SIZE)
                                                             (* ; 
                          "Patch: IFS code has bug that only lets me do a write with length=4 here")
          [COND
             ((LISTP TYPE)                                   (* ; 
                                            "E.g.  (BINARY 16).  Does anyone else know about this?")
              (SETQ BYTESIZE (FIXP (CADR TYPE)))
              (SETQ TYPE (CAR TYPE]
          (replace (LEAFDATA LEAFFILETYPE) of DATA with (SELECTQ TYPE
                                                                        (TEXT \FT.TEXT)
                                                                        (NIL \FT.UNKNOWN)
                                                                        \FT.BINARY))
          (replace (LEAFDATA LEAFBYTESIZE) of DATA with (OR BYTESIZE 10Q))
          (replace (LEAFDATA LEAFLENGTH) of DATA with (IPLUS \LEN.FILEREQUEST 
                                                                         \LEN.FILETYPE&SIZE))
          (\SENDLEAF (fetch (LEAFSTREAM LEAFCONNECTION) of STREAM)
                 OPUP STREAM NIL T)
          (RETURN TYPE])

(\LEAF.SETVALIDATION
  [LAMBDA (STREAM)                            (* ; 
                                                "Edited  2-Nov-92 03:36 by sybalsky:mv:envos")

(* ;;; "Set the VALIDATION field of STREAM based on the file's write and creation dates")

    (replace (STREAM VALIDATION) of STREAM with (\MAKENUMBER (fetch (LEAFINFOBLOCK
                                                                                     LOCREATE)
                                                                            of
                                                                            (fetch (LEAFSTREAM
                                                                                        LEAFINFO)
                                                                               of STREAM))
                                                                   (fetch (LEAFINFOBLOCK LOWRITE)
                                                                      of (fetch (LEAFSTREAM
                                                                                         LEAFINFO)
                                                                                of STREAM])

(\LEAF.TRUNCATEFILE
  [LAMBDA (STREAM LASTPAGE LASTOFF)                      (* ; "Edited 24-May-91 15:08 by jds")

(* ;;; "Truncate file by doing a zero-length write with the EOF bit set")

    (COND
       (LASTPAGE                                             (* ; 
                             "Don't bother if defaulting, we have already set correct length if so")
              (PROG ((OPUP (ALLOCATE.PUP))
                     DATA)
                    (SETQ DATA (fetch PUPCONTENTS of OPUP))
                    (replace (LEAFDATA OPWORD) of DATA with (LLSH \LEAFOP.WRITE 
                                                                              \OPCODE.SHIFT))
                    (replace (LEAFDATA HANDLE) of DATA with (fetch (LEAFSTREAM 
                                                                                          LEAFHANDLE)
                                                                           of STREAM))
                    (replace (LEAFDATA FILEADDRESS) of DATA
                       with (create BYTEPTR
                                       PAGE _ LASTPAGE
                                       OFFSET _ LASTOFF))
                    (replace (LEAFDATA EOFBIT) of DATA with 1)
                    (replace (LEAFDATA DATALENGTH) of DATA with 0)
                    (replace (LEAFDATA LEAFLENGTH) of DATA with \LEN.FILEREQUEST)
                    (\SENDLEAF (fetch (LEAFSTREAM LEAFCONNECTION) of STREAM)
                           OPUP STREAM NIL T)
                    (RETURN STREAM])

(\LEAF.WRITEPAGES
  [LAMBDA (STREAM FIRSTPAGE BUFFERLIST)       (* ; 
                                                "Edited  2-Nov-92 03:36 by sybalsky:mv:envos")
    (COND
       ((fetch (STREAM REVALIDATEFLG) of STREAM)

        (* ;; "Need to update creationdate, since a SAVEVM etc has occurred since the last write.  Otherwise, it is possible to see a change to the file but no change to the creationdate")

        (\LEAF.SETCREATIONDATE STREAM (IDATE))
        (replace (STREAM REVALIDATEFLG) of STREAM with NIL)))
    (for BUF inside BUFFERLIST as PAGE# from FIRSTPAGE
       do (\LEAF.LOOKUPCACHE STREAM PAGE# T)         (* ; 
                                                           "Invalidate any read-ahead of this page")
             (PROG ((OPUP (ALLOCATE.PUP))
                    DATA LEN)
                   (SETQ DATA (fetch PUPCONTENTS of OPUP))
                   (replace (LEAFDATA OPWORD) of DATA with (LLSH \LEAFOP.WRITE 
                                                                             \OPCODE.SHIFT))
                   (replace (LEAFDATA HANDLE) of DATA with (fetch (LEAFSTREAM 
                                                                                         LEAFHANDLE)
                                                                          of STREAM))
                   (replace (LEAFDATA FILEADDRESS) of DATA
                      with (create BYTEPTR
                                      PAGE _ PAGE#
                                      OFFSET _ 0))
                   [replace (LEAFDATA DATALENGTH) of DATA
                      with (SETQ LEN (COND
                                            ((NEQ PAGE# (fetch (STREAM EPAGE) of STREAM))
                                             BYTESPERPAGE)
                                            (T               (* ; 
                                               "On last page, only write as much as we really have")
                                               (replace (LEAFDATA EOFBIT) of DATA
                                                  with 1)
                                               (fetch (STREAM EOFFSET) of STREAM]
                   (\BLT (\ADDBASE DATA (FOLDLO \LEN.FILEREQUEST BYTESPERWORD))
                         BUF
                         (FOLDHI LEN BYTESPERWORD))
                   (replace (LEAFDATA LEAFLENGTH) of DATA with (IPLUS \LEN.FILEREQUEST 
                                                                                  LEN))
                   (\SENDLEAF (fetch (LEAFSTREAM LEAFCONNECTION) of STREAM)
                          OPUP STREAM NIL T])
)



(* ;; "Main routing point for LEAF pups")

(DEFINEQ

(\SENDLEAF
  [LAMBDA (SEQUIN PUP FILENAME NOERROR NOREPLY DONTWAIT)
                                                  (* ; 
                                                "Edited  2-Nov-92 03:36 by sybalsky:mv:envos")
    (PROG (RESULT)
      TOP (OR SEQUIN (RETURN (LISPERROR "FILE NOT OPEN" FILENAME)))
          (COND
             ((AND (type? STREAM FILENAME)
                   (NEQ (fetch (LEAFSTREAM LEAFERRORCNT) of FILENAME)
                        0))
              (ERROR 
            "Attempt to operate on broken file.  Do not proceed until the problem has been resolved."
                     (fetch (STREAM FULLFILENAME) of FILENAME))
              (GO TOP)))
          (replace EPUSERFIELD of PUP with FILENAME)
          [replace (LEAFPACKET LEAFFLAGS) of PUP with (LOGOR (COND
                                                                            (NOERROR \LF.ALLOWERRORS)
                                                                            (T 0))
                                                                         (COND
                                                                            ((EQ NOREPLY T)
                                                                             0)
                                                                            (T \LF.WANTANSWER]
          (replace PUPLENGTH of PUP with (IPLUS (fetch (LEAFDATA LEAFLENGTH)
                                                               of (fetch PUPCONTENTS
                                                                         of PUP))
                                                            \PUPOVLEN))
          (RETURN (COND
                     ((NULL (PUTSEQUIN SEQUIN PUP DONTWAIT))
                      NIL)
                     (NOREPLY T)
                     (T (until (NEQ (fetch EPUSERFIELD of PUP)
                                        FILENAME) do (AWAIT.EVENT (fetch (SEQUIN SEQEVENT)
                                                                         of SEQUIN)
                                                                \ETHERTIMEOUT))
                        (SETQ RESULT (fetch EPUSERFIELD of PUP))
                        (COND
                           ((EQ RESULT \LEAF.BROKEN.STATUS)
                            PUP)
                           (T (replace (LEAFPACKET LEAFSTATUS) of RESULT
                                 with (COND
                                             ((EQ (fetch (LEAFDATA LEAFOPCODE)
                                                     of (fetch PUPCONTENTS of RESULT))
                                                  \LEAFOP.ERROR)
                                              (fetch (LEAFERRORDATA LEAFERRORCODE)
                                                 of (fetch PUPCONTENTS of RESULT)))
                                             (T \LEAF.GOODSTATUS)))
                              (RELEASE.PUP PUP)
                              RESULT])
)



(* ;; "Managing LEAF connections")

(DEFINEQ

(\OPENLEAFCONNECTION
  [LAMBDA (HOST)                                         (* ; "Edited 24-May-91 15:04 by jds")
    (PROG (PROTOCOLS IFSPORT NAME/PASS)
          [COND
             ([OR (MEMB HOST NONLEAFHOSTS)
                  (AND [LISTP (SETQ PROTOCOLS (GETHOSTINFO HOST 'PROTOCOLS]
                       (NOT (MEMB 'LEAF PROTOCOLS]
              (RETURN \LEAF.NEVER.OPENED))
             ((NOT (SETQ IFSPORT (BESTPUPADDRESS HOST PROMPTWINDOW)))
              (RETURN))
             ((EQ (CDR IFSPORT)
                  0)
              (SETQ IFSPORT (CONS (CAR IFSPORT)
                                  \SOCKET.LEAF]
          (SETQ NAME/PASS (\INTERNAL/GETPASSWORD HOST))
          (RETURN (WITH.MONITOR \LEAFCONNECTIONLOCK          (* ; "NOTE: Implicit RESETLST")
                      (PROG (CONN RESULT DATA OPUP)
                            [SETQ CONN (create SEQUIN
                                              SEQNAME _ HOST
                                              SEQFRNPORT _ IFSPORT
                                              SEQACKED _ (FUNCTION \LEAF.ACKED)
                                              SEQINPUT _ (FUNCTION \LEAF.HANDLE.INPUT)
                                              SEQBROKEN _ (FUNCTION \LEAF.FIX.BROKEN.SEQUIN)
                                              SEQABORTED _ (FUNCTION \LEAF.FIX.BROKEN.SEQUIN)
                                              SEQTIMEDOUT _ (FUNCTION \LEAF.TIMEDOUT)
                                              SEQTIMEDIN _ (FUNCTION \LEAF.TIMEDIN)
                                              SEQCLOSED _ (FUNCTION \LEAF.WHENCLOSED)
                                              SEQIDLEFN _ (FUNCTION \LEAF.IDLE)
                                              SEQIDLETIMEOUTCOMPUTER _ (FUNCTION \LEAF.IDLE?)
                                              SEQOPENERRORHANDLER _ (FUNCTION \LEAF.OPENERRORHANDLER)
                                              SEQDONEQ _ (NCREATE 'SYSQUEUE)
                                              LEAFCACHETIMER _ (\CREATECELL \FIXP)
                                              SEQIGNOREDUPLICATES _ T
                                              LEAFOPENCLOSELOCK _ (CREATE.MONITORLOCK (CONCAT HOST 
                                                                                          "#LEAFOPEN"
                                                                                             ]
                            (INITSEQUIN CONN (PACK* HOST "#LEAF"))
                            (replace (SEQUIN LEAFCACHEHITS) of CONN with 0)
                            (replace (SEQUIN LEAFCACHEMISSES) of CONN with 0)
                            (RESETSAVE NIL (LIST [FUNCTION (LAMBDA (SEQUIN)
                                                             (AND RESETSTATE (\SEQUIN.CLOSE
                                                                              SEQUIN]
                                                 CONN))
                        RETRY
                            (PROGN (SETQ OPUP (ALLOCATE.PUP))(* ; "Build a LEAF RESET op")
                                   (SETQ DATA (fetch PUPCONTENTS of OPUP))
                                   (\CLEARBYTES DATA 0 \LEN.RESETLEAF)
                                   (replace (LEAFDATA LEAFOPCODE) of DATA with 
                                                                                        \LEAFOP.RESET
                                          )
                                   (replace (LEAFDATA LEAFLENGTH) of DATA with 
                                                                                       \LEN.RESETLEAF
                                          )
                                   (\ADDLEAFSTRING OPUP (CAR NAME/PASS))
                                   (\ADDLEAFSTRING OPUP (CDR NAME/PASS)
                                          T)
                                   (replace PUPLENGTH of OPUP
                                      with (+ (fetch (LEAFDATA LEAFLENGTH) of DATA)
                                                  \PUPOVLEN)))
                            (replace EPUSERFIELD of OPUP with NIL)
                            (replace (LEAFPACKET LEAFFLAGS) of OPUP with (LOGOR 
                                                                                      \LF.ALLOWERRORS
                                                                                            
                                                                                       \LF.WANTANSWER
                                                                                            ))
                            (PUTSEQUIN CONN OPUP)
                            (until (SELECTC (fetch (SEQUIN SEQSTATE) of CONN)
                                           (\SS.OPENING      (* ; "still waiting for an answer")
                                                        NIL)
                                           (\SS.OPEN         (* ; 
                                    "Connection has become open, or already was if this is a retry")
                                                     (SETQ RESULT (fetch EPUSERFIELD of
                                                                                         OPUP)))
                                           (PROGN            (* ; "Some bad state")
                                                  (SETQ RESULT (fetch EPUSERFIELD of OPUP))
                                                  T)) do (AWAIT.EVENT (fetch (SEQUIN SEQEVENT
                                                                                            )
                                                                             of CONN)
                                                                    \ETHERTIMEOUT))
                            (SELECTC RESULT
                                ((LIST NIL \LEAF.BROKEN.STATUS) 
                                     (RETURN NIL))
                                (\LEAF.NEVER.OPENED 
                                     (RETURN \LEAF.NEVER.OPENED))
                                NIL)
                            (COND
                               ((EQ (fetch (LEAFDATA LEAFOPCODE) of (fetch PUPCONTENTS
                                                                               of RESULT))
                                    \LEAFOP.ERROR)
                                (SELECTC (SETQ RESULT (PROG1 (fetch (LEAFERRORDATA LEAFERRORCODE)
                                                                of (fetch PUPCONTENTS
                                                                          of RESULT))
                                                             (RELEASE.PUP RESULT)))
                                    (\PASSWORD.ERRORS        (* ; "Password error")
                                         (COND
                                            ((SETQ NAME/PASS (\FIXPASSWORD RESULT CONN))
                                             (GO RETRY))))
                                    NIL)
                                (\SEQUIN.CLOSE CONN)
                                (RETURN NIL)))
                            (RELEASE.PUP RESULT)
                            (LET [(TIMEOUT (TIMES 2 (IQUOTIENT \LEAF.IDLETIMEOUT 11610Q]

                                 (* ;; "Build a LEAF PARAMS op, making the connection timeout be twice the time that we would time it out ourselves (so as to reduce the likelihood that the server would kill us without our consent).")

                                 (SETQ OPUP (ALLOCATE.PUP))
                                 (SETQ DATA (fetch PUPCONTENTS of OPUP))
                                 (\CLEARBYTES DATA 0 \LEN.LEAFPARAMS)
                                 (replace (LEAFDATA LEAFOPCODE) of DATA with 
                                                                                      \LEAFOP.PARAMS)
                                 (replace (LEAFDATA LEAFLENGTH) of DATA with 
                                                                                      \LEN.LEAFPARAMS
                                        )
                                 (replace (LEAFPARAMSDATA LEAFPCONNTIMEOUT) of DATA
                                    with TIMEOUT)
                                 (replace (LEAFPARAMSDATA LEAFPLOCKTIMEOUT) of DATA
                                    with TIMEOUT)        (* ; 
             "Make lock timeout the same, so we don't have silly lock broken stuff to worry about.")
                                 (replace PUPLENGTH of OPUP with (+ \LEN.LEAFPARAMS 
                                                                                \PUPOVLEN)))
                            (replace EPUSERFIELD of OPUP with NIL)
                            (replace (LEAFPACKET LEAFFLAGS) of OPUP with \LF.ALLOWERRORS)
                            (PUTSEQUIN CONN OPUP)
                            (RETURN CONN)))])

(\LEAF.BREAKCONNECTION
  [LAMBDA (HOST DEVICE FAST)                             (* ; "Edited 24-May-91 15:12 by jds")

(* ;;; "Breaks connection to host, if there is one.  Returns T if it broke something, NIL if there was nothing to break.  If FAST is true, does not attempt to cleanly close any files open on the host")

    (LET (CONNECTION FILES DEVINFO)
         (COND
            ((AND (type? PUPFILESERVER (SETQ DEVINFO (fetch DEVICEINFO of DEVICE)))
                  (SETQ CONNECTION (fetch (PUPFILESERVER PFSLEAFSEQUIN) of DEVINFO)))
             [COND
                ((SETQ FILES (FDEVOP 'OPENP DEVICE NIL NIL DEVICE))
                 (COND
                    (FAST (for S in FILES do (FDEVOP 'UNREGISTERFILE DEVICE DEVICE S)))
                    (T (MAPC FILES (FUNCTION CLOSEF]
             (\CLOSELEAFCONNECTION CONNECTION DEVICE])

(\CLOSELEAFCONNECTION
  [LAMBDA (CONN DEVICE)                                  (* ; "Edited 24-May-91 14:53 by jds")
    (PROG1 [COND
              ((CLOSESEQUIN CONN)
               (fetch (SEQUIN SEQNAME) of CONN))
              (T (LIST (fetch (SEQUIN SEQNAME) of CONN)
                       'aborted]
        (replace (LEAFDEVICE PFSLEAFSEQUIN) of DEVICE with NIL))])

(\LEAF.EVENTFN
  [LAMBDA (FDEV EVENT-TYPE)                              (* ; "Edited 24-May-91 15:12 by jds")

(* ;;; "Called before LOGOUT etc to clean up any leaf connections we have open")

    (PROG ((DEVINFO (fetch DEVICEINFO of FDEV))
           CONNECTION SOC)
          (SELECTQ EVENT-TYPE
              ((BEFORELOGOUT BEFOREMAKESYS BEFORESYSOUT) 
                   (COND
                      ((SETQ CONNECTION (fetch (PUPFILESERVER PFSLEAFSEQUIN) of DEVINFO))
                       (\FLUSH.OPEN.STREAMS FDEV)

                       (* ;; "Would like to have a monitor on this to prevent other processes from writing files now, but it can't be the main sequin lock")

                       (\CLOSELEAFCONNECTION CONNECTION FDEV))))
              ((AFTERLOGOUT AFTERMAKESYS AFTERSYSOUT AFTERSAVEVM) 
                   (COND
                      ((SETQ CONNECTION (fetch (PUPFILESERVER PFSLEAFSEQUIN) of DEVINFO))
                       (\SEQUIN.FLUSH.CONNECTION CONNECTION \SS.ABORT)))
                   (COND
                      ((NOT (FDEVOP 'OPENP FDEV NIL NIL FDEV))

                       (* ;; "Association between hostname and host goes away over logout, so flush it.  If there is a file open on it, however, assume it's okay")

                       (\REMOVEDEVICE FDEV)))
                   (COND
                      ((SETQ SOC (fetch (PUPFILESERVER PFSLOOKUPFILESOCKET) of DEVINFO))
                       (CLOSEPUPSOCKET SOC)
                       (replace (PUPFILESERVER PFSLOOKUPFILESOCKET) of DEVINFO with
                                                                                       NIL)))
                   (replace (PUPFILESERVER PFSLOOKUPFILELOCK) of DEVINFO with NIL)
                                                             (* ; "revalidate open files")
                   (\PAGED.REVALIDATEFILELST FDEV))
              NIL])
)



(* ; "This generic fn ought to be on FILEIO")

(DEFINEQ

(BREAKCONNECTION
  [LAMBDA (HOST FAST)                                    (* ; "Edited 23-Dec-87 12:29 by bvm:")

(* ;;; "User entry.  Breaks connection to host, if there is one, or all hosts if host = t.  Returns name of any device that handled it.  If FAST is true, may not attempt to cleanly close any files open on the host")

    (LET (DEVICE BREAKFN)
         (COND
            ((EQ HOST T)
             (for DEV in \FILEDEVICES when (AND (SETQ BREAKFN (fetch BREAKCONNECTION
                                                                             of DEV))
                                                            (CL:FUNCALL BREAKFN (fetch DEVICENAME
                                                                                   of DEV)
                                                                   DEV FAST))
                collect (fetch DEVICENAME of DEV)))
            ((AND [OR (SETQ DEVICE (\GETDEVICEFROMNAME HOST T T))
                      (AND (SETQ HOST (CANONICAL.HOSTNAME HOST))
                           (SETQ DEVICE (\GETDEVICEFROMNAME HOST T T]
                  (SETQ BREAKFN (fetch BREAKCONNECTION of DEVICE))
                  (CL:FUNCALL BREAKFN (fetch DEVICENAME of DEVICE)
                         DEVICE FAST))
             (fetch DEVICENAME of DEVICE])
)



(* ;; "Functions called when various SEQUIN events occur")

(DEFINEQ

(\LEAF.ACKED
  [LAMBDA (PUP SEQUIN)                                   (* ; "Edited 24-May-91 14:53 by jds")

    (* ;; "Called when a packet has been acked")

    (\ENQUEUE (fetch (SEQUIN SEQDONEQ) of SEQUIN)
           PUP)
    (add (fetch (SEQUIN SEQINPUTQLENGTH) of SEQUIN)
           1])

(\LEAF.FIX.BROKEN.SEQUIN
  [LAMBDA (SEQUIN PUP)                                   (* ; "Edited 24-May-91 15:08 by jds")

    (* ;; 
  "Called when BROKEN received.  Try to open a new connection, and transfer everything over")

    (PROG ((STATE (fetch (SEQUIN SEQSTATE) of SEQUIN))
           (RETRANSQ (fetch (SEQUIN SEQRETRANSMITQ) of SEQUIN))
           (ACKEDQ (fetch (SEQUIN SEQDONEQ) of SEQUIN))
           (DEVICE (\GETDEVICEFROMNAME (fetch (SEQUIN SEQNAME) of SEQUIN)))
           UNANSWEREDPUPS AFFECTEDFILES NEWCONNECTION STRM)
          (\SEQUIN.FLUSH.RETRANSMIT SEQUIN)
          (COND
             (PUP                                            (* ; 
                                                       "Attempt to send PUP on a broken connection")
                  (GO GET.NEW.CONNECTION)))
          [COND
             ((SETQ UNANSWEREDPUPS (fetch SYSQUEUEHEAD of ACKEDQ))
                                                             (* ; 
             "There were acked but not answered packets, so process them ahead of the unacked ones")
              (replace EPLINK of (fetch SYSQUEUETAIL of ACKEDQ)
                 with (fetch SYSQUEUEHEAD of RETRANSQ))
              (replace SYSQUEUEHEAD of ACKEDQ with (replace SYSQUEUETAIL of
                                                                                         ACKEDQ
                                                                  with NIL)))
             (T (SETQ UNANSWEREDPUPS (fetch SYSQUEUEHEAD of RETRANSQ]
          (SELECTC STATE
              (\SS.OPENING 
                           (* ;; "Probably means we crashed on this local machine a while back using exactly the same socket number, so leaf thinks we're confused.  This virtually never happens now that we choose Pup sockets more cleverly")

                           (COND
                              ((AND UNANSWEREDPUPS (NOT (fetch EPLINK of UNANSWEREDPUPS))
                                    (EQ (fetch (LEAFDATA LEAFOPCODE) of (fetch 
                                                                                       PUPCONTENTS
                                                                                   of 
                                                                                       UNANSWEREDPUPS
                                                                                       ))
                                        \LEAFOP.RESET))
                               [replace (SEQUIN SEQSOCKET) of SEQUIN
                                  with (PROG1 (OPENPUPSOCKET)
                                                             (* ; "Get a new socket and try again")
                                               (CLOSEPUPSOCKET (fetch (SEQUIN SEQSOCKET)
                                                                  of SEQUIN)))]
                               (replace PUPSOURCESOCKET of UNANSWEREDPUPS with 0)
                                                             (* ; 
                                                           "Let SENDPUP fill in the new socket")
                               (RETURN (\SEQUIN.RETRANSMIT SEQUIN)))
                              (T (GO FAILURE))))
              ((LIST \SS.OPEN \SS.CLOSING) 
                   (COND
                      ((NULL UNANSWEREDPUPS)                 (* ; 
                       "No activity has gone unanswered here, so safe to just abort the connection")
                       (\SEQUIN.FLUSH.CONNECTION SEQUIN)
                       (RETURN T))))
              (GO FAILURE))

     (* ;; "This SEQUIN is bad, probably because of a file server crash (or we were idle a long time and it timed us out) so flush it and try to establish a new one, retransmitting anything that wasn't yet answered")

          (replace SYSQUEUEHEAD of RETRANSQ with (replace SYSQUEUETAIL of 
                                                                                             RETRANSQ
                                                                with NIL))
                                                             (* ; 
                                                "Detach old queues of packets from dead connection")
          (printout PROMPTWINDOW "[Connection with " (fetch (SEQUIN SEQNAME) of SEQUIN)
                 " crashed; " "trying to establish new connection...")
      GET.NEW.CONNECTION
          (SETQ AFFECTEDFILES (for STREAM in (FDEVOP 'OPENP DEVICE NIL NIL DEVICE)
                                 collect STREAM when (EQ (fetch (LEAFSTREAM 
                                                                                   LEAFCONNECTION)
                                                                    of STREAM)
                                                                 SEQUIN)))
      RETRY.NEW.CONNECTION
          [COND
             ([SETQ NEWCONNECTION (\LEAF.RECONNECT DEVICE
                                         (AND (EQ (fetch (SEQUIN LEAFABORTSTATUS) of SEQUIN)
                                                  'ABORT)
                                              (NOT (\CLOCKGREATERP (fetch (SEQUIN SEQTIMER)
                                                                      of SEQUIN)
                                                          \LEAF.RECOVERY.TIMEOUT]
                                                             (* ; 
                                          "Succeeded in getting a new connection, so restore files")
              (\SEQUIN.FLUSH.CONNECTION SEQUIN)
              [COND
                 ((AND \WINDOWWORLD (NOT (HASTTYWINDOWP)))

                  (* ;; "Assure that output from what follows has enough space to print.  Note that this does not actually open the window (though it may create it).  Also, we don't care about restoration on exit, because this process is doomed anyway.")

                  (WINDOWPROP T 'PAGEFULLFN (FUNCTION EXPANDING-PAGEFULLFN]
              (COND
                 (PUP                                        (* ; 
                                                       "Attempt to send PUP on a broken connection")
                      (AND AFFECTEDFILES (\PAGED.REVALIDATEFILELST DEVICE))
                      (RETURN (\LEAF.REPAIR.BROKEN.PUP SEQUIN PUP)))
                 ((NOT (SETQ UNANSWEREDPUPS (\LEAF.USE.NEW.CONNECTION NEWCONNECTION 
                                                   UNANSWEREDPUPS AFFECTEDFILES)))
                  (printout PROMPTWINDOW "done]" T)
                  (RETURN T]
          (COND
             ((NULL (fetch (SEQUIN LEAFABORTBUTTONWINDOW) of SEQUIN))
              (\SEQUIN.FLUSH.CONNECTION SEQUIN))
             ((forDuration 165140Q do (COND
                                                 ((EQ (fetch (SEQUIN LEAFABORTSTATUS)
                                                         of SEQUIN)
                                                      'ABORT)
                                                  (\SEQUIN.FLUSH.CONNECTION SEQUIN)
                                                  (RETURN T)))
                                             (AWAIT.EVENT (fetch (SEQUIN SEQEVENT) of SEQUIN)
                                                    11610Q))
              (RETURN))
             (T (GO RETRY.NEW.CONNECTION)))

     (* ;; "Either failed to make the new connection or something happened to the file")

      FAILURE
          [ERROR "File server connection has been broken--cannot complete file operation(s).  (RETURN) to try again to get a new connection."
                 (COND
                    ((AND PUP (SETQ STRM (fetch EPUSERFIELD of PUP)))
                     (.NAMEORSTREAM. STRM))
                    (T (fetch (SEQUIN SEQNAME) of SEQUIN]
          (GO RETRY.NEW.CONNECTION])

(\LEAF.REPAIR.BROKEN.PUP
  [LAMBDA (OLDSEQUIN PUP)                     (* ; 
                                                "Edited  2-Nov-92 03:37 by sybalsky:mv:envos")

    (* ;; "PUP is a pup that we were trying to send on a dead sequin.  If we have since established the new connection, there is a new sequin in PUP's stream, and we can patch the pup.  Returns the new connection, or NIL if it can't")

    (PROG ((STREAM (fetch EPUSERFIELD of PUP))
           NEWCONNECTION DATA)
          [COND
             ((OR (NULL STREAM)
                  (NOT (type? STREAM STREAM)))           (* ; "Not much to go on")
              )
             ((AND (SETQ NEWCONNECTION (fetch (LEAFSTREAM LEAFCONNECTION) of STREAM))
                   (NEQ NEWCONNECTION OLDSEQUIN)
                   (SELECTC (fetch (LEAFDATA LEAFOPCODE) of (SETQ DATA (fetch PUPCONTENTS
                                                                                  of PUP)))
                       ((LIST \LEAFOP.READ \LEAFOP.WRITE \LEAFOP.TRUNCATE \LEAFOP.DELETE 
                              \LEAFOP.CLOSE)                 (* ; 
                                         "These operations all have their handle in the same place")
                            (replace (LEAFDATA HANDLE) of DATA with (fetch
                                                                                 (LEAFSTREAM 
                                                                                        LEAFHANDLE)
                                                                                   of STREAM))
                            T)
                       NIL))
              (RETURN NEWCONNECTION))
             (T (ERROR "File server connection broken" (OR (fetch (STREAM FULLFILENAME)
                                                              of STREAM)
                                                           STREAM]
          (replace (LEAFPACKET LEAFSTATUS) of PUP with \LEAF.BROKEN.STATUS)
          (RETURN NIL])

(\LEAF.USE.NEW.CONNECTION
  [LAMBDA (SEQUIN UNSENTPUPS AFFECTEDFILES)   (* ; 
                                                "Edited  2-Nov-92 03:37 by sybalsky:mv:envos")
    (PROG (BUSYFILES OPCODE OLDSTREAM PUP DATA GOODPUPS BADPUPS RESENDPUPS)
          (while UNSENTPUPS do [SETQ PUP (COND
                                                    ((LISTP UNSENTPUPS)
                                                             (* ; 
                                  "We're given a list of packets, so hand them back one at a time.")
                                                     (POP UNSENTPUPS))
                                                    (T       (* ; 
                                       "Given a single packet, follow the normal queue line field.")
                                                       (PROG1 UNSENTPUPS
                                                           (SETQ UNSENTPUPS (fetch EPLINK
                                                                               of UNSENTPUPS)))]
                                      (replace EPLINK of PUP with NIL)
                                      (SELECTC [SETQ OPCODE (fetch (LEAFDATA LEAFOPCODE)
                                                               of (SETQ DATA
                                                                       (fetch PUPCONTENTS
                                                                          of PUP]
                                          ((LIST \LEAFOP.READ \LEAFOP.WRITE \LEAFOP.TRUNCATE 
                                                 \LEAFOP.DELETE) 
                                                             (* ; 
                                         "These operations all have their handle in the same place")
                                               (COND
                                                  ((SETQ OLDSTREAM (fetch EPUSERFIELD
                                                                      of PUP))
                                                   (pushnew AFFECTEDFILES OLDSTREAM)
                                                   (pushnew BUSYFILES OLDSTREAM)
                                                   (push GOODPUPS PUP))
                                                  (T         (* ; "Shouldn't happen")
                                                     (push BADPUPS PUP))))
                                          (\LEAFOP.CLOSE [COND
                                                            ((SETQ OLDSTREAM (fetch EPUSERFIELD
                                                                                of PUP))
                                                             (COND
                                                                ((FMEMB OLDSTREAM BUSYFILES)
                                                             (* ; 
                                    "There are other operations on this file, so include the close")
                                                                 (push GOODPUPS PUP))
                                                                ((DIRTYABLE OLDSTREAM)
                                                                 (push BUSYFILES OLDSTREAM))
                                                                (T 
                                                             (* ; 
                                                 "Closing a file open only for read;  don't bother")
                                                                   (SETQ AFFECTEDFILES
                                                                    (DREMOVE OLDSTREAM AFFECTEDFILES])
                                          (\LEAFOP.OPEN 

                                 (* ;; "just trying to open a file, so should work fine with the new connection;  however, \LEAF.GETFILE needs to know to use the new connection, so easier to just mark it broken here")

                                                        (replace (LEAFPACKET LEAFSTATUS)
                                                           of PUP with \LEAF.BROKEN.STATUS))
                                          (push BADPUPS PUP)))
          (for STREAM in (UNION BUSYFILES AFFECTEDFILES) when (DIRTYABLE STREAM)
             do (printout T T "*****Warning: " (fetch (STREAM FULLFILENAME) of STREAM)
                           " was open for write during a file server crash; data may be lost" T T))
          (COND
             (AFFECTEDFILES (SETQ AFFECTEDFILES (\PAGED.REVALIDATEFILES AFFECTEDFILES))
                                                             (* ; 
                         "Reopen those files, make sure they still exist and haven't been modified")
                    ))
          [for PUP in GOODPUPS do                (* ; "Do operation with new handle")
                                             (COND
                                                ((FMEMB (SETQ OLDSTREAM (fetch EPUSERFIELD
                                                                           of PUP))
                                                        AFFECTEDFILES)
                                                 (replace (LEAFDATA HANDLE)
                                                    of (fetch PUPCONTENTS of PUP)
                                                    with (fetch (LEAFSTREAM LEAFHANDLE)
                                                                of OLDSTREAM))
                                                 (push RESENDPUPS PUP))
                                                (T (push BADPUPS PUP]
          [COND
             (RESENDPUPS (ADD.PROCESS (LIST '\LEAF.RESENDPUPS (KWOTE SEQUIN)
                                            (KWOTE RESENDPUPS]
          (RETURN BADPUPS])

(\LEAF.RESENDPUPS
  [LAMBDA (SEQUIN PUPS)                                  (* bvm%: "17-APR-83 18:10")
    (while PUPS do (replace PUPSOURCESOCKET of (CAR PUPS) with 0)
                          (PUTSEQUIN SEQUIN (pop PUPS])

(\LEAF.HANDLE.INPUT
  [LAMBDA (PUP SEQUIN)                                   (* ; "Edited 24-May-91 15:08 by jds")
                                                             (* ; 
                                                           "Called when a data sequin arrives")
    (PROG ((PUPDATA (fetch PUPCONTENTS of PUP))
           DONEPUP DONEPUPDATA ERROR OPCODE STREAM)

     (* ;; "Under current scheme, where every requesting packet is responded to by exactly one packet, we 'know' that PUP matches up with the head of SEQDONEQ.  The error checking here is thus for protocol violation and is optional")

          (SETQ DONEPUP (\DEQUEUE (fetch (SEQUIN SEQDONEQ) of SEQUIN)))
          [COND
             ((NOT DONEPUP)
              (RETURN (SHOULDNT "Leaf lost a packet somewhere!"]
          (add (fetch (SEQUIN SEQINPUTQLENGTH) of SEQUIN)
                 -1)
          [COND
             ((EQ (fetch (LEAFDATA ANSWERBIT) of PUPDATA)
                  0)
              (HELP "Leaf Protocol violation--will terminate connection" (fetch (SEQUIN SEQNAME)
                                                                            of SEQUIN))
              (RETURN (RELEASE.PUP PUP]
          (COND
             ((EQ (SETQ OPCODE (fetch (LEAFDATA LEAFOPCODE) of PUPDATA))
                  \LEAFOP.ERROR)
              (SETQ OPCODE (fetch (LEAFERRORDATA LEAFERROROPCODE) of PUPDATA))
              (SETQ ERROR T)))
          (COND
             ((AND (NEQ (fetch (LEAFDATA LEAFOPCODE) of (SETQ DONEPUPDATA
                                                                 (fetch PUPCONTENTS of 
                                                                                              DONEPUP
                                                                        )))
                        OPCODE)
                   LEAFDEBUGFLG)                             (* ; 
                                           "Protocol violation, but the buggy Vax server does this")
              (HELP "Answer does not match head of done queue" PUP))
             ([AND ERROR (NOT (fetch (LEAFPACKET LEAFALLOWERRORS) of DONEPUP))
                   (NOT (AND (EQ OPCODE \LEAFOP.CLOSE)
                             (EQ (fetch (LEAFERRORDATA LEAFERRORCODE) of PUPDATA)
                                 \IFSERROR.BAD.HANDLE]

              (* ;; "Last clause says that if we were closing the file and got a bad handle error, to ignore it -- this typically happens if two files try to close the same file simultaneously")

              (replace (LEAFPACKET LEAFSTATUS) of PUP with (fetch (LEAFERRORDATA
                                                                                   LEAFERRORCODE)
                                                                          of DONEPUPDATA))
              (SETQ STREAM (fetch EPUSERFIELD of DONEPUP))
              (COND
                 ((type? STREAM STREAM)
                  (add (fetch (LEAFSTREAM LEAFERRORCNT) of STREAM)
                         1)))
              (replace EPUSERFIELD of DONEPUP with PUP)
              (ADD.PROCESS (LIST (FUNCTION \LEAF.ERROR)
                                 PUP
                                 (KWOTE STREAM)
                                 SEQUIN DONEPUP)))
             ((fetch (LEAFPACKET LEAFANSWERWANTED) of DONEPUP)

              (* ;; "Match the request with its response;  requestor will watch this slot.  Eventually change this to a NOTIFY")

              (replace EPUSERFIELD of DONEPUP with PUP))
             (T (RELEASE.PUP PUP)
                (RELEASE.PUP DONEPUP])

(\LEAF.OPENERRORHANDLER
  [LAMBDA (SEQUIN PUP)                                   (* ; "Edited 24-May-91 14:54 by jds")
    (SELECTC (fetch ERRORPUPCODE of PUP)
        (\PUPE.NOSOCKET 
             (printout PROMPTWINDOW T "[No Leaf Server on " (fetch (SEQUIN SEQNAME) of SEQUIN
                                                                   ))
             (COND
                (\FTPAVAILABLE (printout PROMPTWINDOW "; trying FTP...")))
             (printout PROMPTWINDOW "]")
             \SS.NOSOCKET)
        (\PUPE.NOROUTE (printout PROMPTWINDOW T "[No route to " (fetch (SEQUIN SEQNAME)
                                                                   of SEQUIN)
                              "]")
                       T)
        NIL])

(\LEAF.TIMEDIN
  [LAMBDA (SEQUIN)                                       (* ; "Edited 24-May-91 14:54 by jds")
    (COND
       ((fetch (SEQUIN LEAFABORTBUTTONWINDOW) of SEQUIN)
        (CLOSEW (fetch (SEQUIN LEAFABORTBUTTONWINDOW) of SEQUIN))
        (replace (SEQUIN LEAFABORTBUTTONWINDOW) of SEQUIN with NIL)
        (replace (SEQUIN LEAFABORTSTATUS) of SEQUIN with NIL)))
    (replace (SEQUIN LEAFTIMEOUTSTATUS) of SEQUIN with NIL])

(\LEAF.TIMEDOUT
  [LAMBDA (SEQUIN CNT)                                   (* ; "Edited 24-May-91 14:54 by jds")
                                                             (* ; "The SEQTIMEDOUT fn for LEAF")
    (COND
       ((EQ (fetch (SEQUIN LEAFABORTSTATUS) of SEQUIN)
            'ABORT)
        (\SEQUIN.CONTROL SEQUIN \SEQUIN.BROKEN)
        (\SEQUIN.FLUSH.CONNECTION SEQUIN))
       ((>= CNT \MAXLEAFTRIES)
        (PROG ((TRIES (fetch (SEQUIN LEAFTIMEOUTSTATUS) of SEQUIN))
               (STATE (fetch (SEQUIN SEQSTATE) of SEQUIN))
               PUP)
              (if (NULL TRIES)
                  then                                   (* ; "First time partner is slow")
                        (SELECTC STATE
                            (\SS.OPENING                     (* ; "can't open connection")
                                         (\LEAF.NOT.RESPONDING SEQUIN :OPEN PROMPTWINDOW)
                                         (\SEQUIN.FLUSH.CONNECTION SEQUIN))
                            (\SS.OPEN (if (SETQ PUP (\LEAF.STREAM.IN.QUEUE SEQUIN))
                                          then           (* ; "Something is going on worth mentioning.  If the only thing in the queue is us trying to close the cache, say, we keep quiet")
                                                (\LEAF.NOT.RESPONDING SEQUIN PUP PROMPTWINDOW)
                                                (COND
                                                   (PUPTRACEFLG (\LEAF.NOT.RESPONDING SEQUIN PUP
                                                                       PUPTRACEFILE)
                                                          (TERPRI PUPTRACEFILE)))
                                                (replace (SEQUIN LEAFTIMEOUTSTATUS) of SEQUIN
                                                   with CNT)))
                            (\SS.CLOSING [COND
                                            ((NULL (SETQ PUP (\LEAF.STREAM.IN.QUEUE SEQUIN T)))
                                                             (* ; 
                                  "Safe to abort connection, since no information left to be acked")
                                             (COND
                                                (PUPTRACEFLG (printout PUPTRACEFILE T 
                                                                    "[File server connection to "
                                                                    (fetch (SEQUIN SEQNAME)
                                                                       of SEQUIN)
                                                                    " aborted]")))
                                             (RETURN (\SEQUIN.FLUSH.CONNECTION SEQUIN]
                                         (\LEAF.NOT.RESPONDING SEQUIN PUP PROMPTWINDOW))
                            NIL)
                elseif (EQ CNT (+ TRIES \MAXLEAFTRIES))
                  then                                   (* ; 
                                                           "Enough, already, better let us get out")
                        (\LEAF.TIMEDOUT.EXCESSIVE SEQUIN CNT])

(\LEAF.NOT.RESPONDING
  [LAMBDA (SEQUIN REASON OUTSTREAM)                      (* ; "Edited 24-May-91 14:54 by jds")

    (* ;; "Alearts user that connection not responding.  REASON is from some unacked packet in the queue, or :OPEN if trying to open the connection.")

    (printout OUTSTREAM T "[" (fetch (SEQUIN SEQNAME) of SEQUIN)
           " not responding")
    (SELECTQ REASON
        (T                                                   (* ; 
                                             "T means those silly nonsense name directory requests"))
        (:OPEN (printout OUTSTREAM " to Leaf connection attempt"))
        (printout OUTSTREAM " for " (.NAMEORSTREAM. REASON)))
    (printout OUTSTREAM "]"])

(\LEAF.TIMEDOUT.EXCESSIVE
  [LAMBDA (SEQUIN CNT)                        (* ; 
                                                "Edited  2-Nov-92 03:37 by sybalsky:mv:envos")
    (AND (WINDOWWORLDP)
         (PROG ([W (CREATEW (MAKEWITHINREGION LEAFABORTREGION)
                          (CONCAT "Leaf Abort window for " (fetch (SEQUIN SEQNAME) of SEQUIN]
                (PUP (fetch SYSQUEUEHEAD of (fetch (SEQUIN SEQDONEQ) of SEQUIN)))
                (FIRSTTIME T)
                READFILES WRITEFILES X DATA PAGE FULLNAME)
               (replace (SEQUIN LEAFABORTBUTTONWINDOW) of SEQUIN with W)
               (printout W (fetch (SEQUIN SEQNAME) of SEQUIN)
                      " is not responding." T)
               (PROG NIL
                 LP  [COND
                        [(NULL PUP)
                         (COND
                            (FIRSTTIME (SETQ FIRSTTIME NIL)
                                   (SETQ PUP (fetch SYSQUEUEHEAD of (fetch (SEQUIN 
                                                                                       SEQRETRANSMITQ
                                                                                              )
                                                                               of SEQUIN)))
                                   (GO LP))
                            (T (for ENTRY in WRITEFILES
                                  do (printout W T "Writing page")
                                        (COND
                                           ((CDDR ENTRY)
                                            (PRIN1 "s" W)))
                                        (MAPRINT (CDR ENTRY)
                                               W " " NIL ", ")
                                        (printout W " of " (CAR ENTRY)))
                               (RETURN]
                        ([AND (SETQ X (fetch EPUSERFIELD of PUP))
                              (OR (NOT (type? STREAM X))
                                  (SETQ FULLNAME (fetch (STREAM FULLFILENAME) of X]
                         (COND
                            ((AND (type? STREAM X)
                                  (SELECTC (fetch (LEAFDATA LEAFOPCODE)
                                              of (fetch PUPCONTENTS of PUP))
                                      (\LEAFOP.WRITE (SETQ PAGE
                                                      (IPLUS (FOLDLO (fetch (LEAFDATA LOADDR)
                                                                        of (SETQ DATA
                                                                                (fetch 
                                                                                       PUPCONTENTS
                                                                                   of PUP)))
                                                                    BYTESPERPAGE)
                                                             (LLSH (SIGNED (fetch (LEAFDATA
                                                                                       JUSTHIADDR)
                                                                              of DATA)
                                                                          BITSPERWORD)
                                                                   7)))
                                                     T)
                                      ((LIST \LEAFOP.CLOSE \LEAFOP.TRUNCATE) 
                                           (AND (DIRTYABLE X)
                                                (SETQ PAGE 'EOF)))
                                      NIL))
                             (for ENTRY in WRITEFILES
                                do [COND
                                          ((EQ (CAR ENTRY)
                                               FULLNAME)
                                           (RETURN (RPLACD ENTRY (CONS PAGE (CDR ENTRY]
                                finally (push WRITEFILES (LIST FULLNAME PAGE)))
                             (pushnew READFILES FULLNAME))
                            ((AND FULLNAME (NOT (FMEMB FULLNAME READFILES)))
                             (printout W T "Reading " FULLNAME)
                             (push READFILES FULLNAME]
                     (SETQ PUP (fetch EPLINK of PUP))
                     (GO LP))
               (printout W T T "... will keep trying." T "If you do not wish to wait for the server to resume operation, you can abort the connection by clicking ABORT below"
                      T)
               (ADDMENU (create MENU
                               ITEMS _ '(ABORT)
                               WHENSELECTEDFN _ (FUNCTION \LEAF.ABORT.FROMMENU))
                      W
                      (create POSITION
                             XCOORD _ (IQUOTIENT (IDIFFERENCE (WINDOWPROP W 'WIDTH)
                                                        (STRINGWIDTH 'ABORT MENUFONT))
                                             2)
                             YCOORD _ 12Q))
               (WINDOWPROP W 'SEQUIN SEQUIN)
               (WINDOWPROP W 'CLOSEFN (FUNCTION (LAMBDA (WINDOW)
                                                  (WINDOWPROP WINDOW 'SEQUIN NIL])

(\LEAF.ABORT.FROMMENU
  [LAMBDA (ITEM MENU BUTTON)                             (* ; "Edited 24-May-91 14:54 by jds")
    (PROG ((WINDOW (WFROMMENU MENU))
           SEQUIN)
          (COND
             ([AND WINDOW (SETQ SEQUIN (WINDOWPROP WINDOW 'SEQUIN]
              (SHADEITEM 'ABORT MENU GRAYSHADE)
              (replace (SEQUIN LEAFABORTSTATUS) of SEQUIN with 'ABORT)
              (NOTIFY.EVENT (fetch (SEQUIN SEQEVENT) of SEQUIN])

(\LEAF.STREAM.IN.QUEUE
  [LAMBDA (SEQUIN IMPORTANT)                  (* ; 
                                                "Edited  2-Nov-92 03:37 by sybalsky:mv:envos")

    (* ;; "Examines queue of SEQUIN requests that have not yet been answered, and returns one that has a stream associated with it.  If IMPORTANT is true, only returns one with 'important' operations pending: write request, or close request for a file that is open for write")

    (PROG ((PUP (fetch SYSQUEUEHEAD of (fetch (SEQUIN SEQDONEQ) of SEQUIN)))
           (FIRSTTIME T)
           DEFAULT X)
      LP  (COND
             [(NULL PUP)
              (COND
                 (FIRSTTIME (SETQ FIRSTTIME NIL)
                        (SETQ PUP (fetch SYSQUEUEHEAD of (fetch (SEQUIN SEQRETRANSMITQ)
                                                                    of SEQUIN)))
                        (GO LP))
                 (T (RETURN DEFAULT]
             ((AND (SETQ X (fetch EPUSERFIELD of PUP))
                   (OR (NOT (type? STREAM X))
                       (fetch (STREAM FULLFILENAME) of X))
                   (if (NOT IMPORTANT)
                       then (if (EQ X T)
                                    then                 (* ; 
                                    "Directorynamep silliness, only use it if it's the only choice")
                                          (SETQ DEFAULT T)
                                          NIL
                                  else T)
                     elseif (type? STREAM X)
                       then (SELECTC (fetch (LEAFDATA LEAFOPCODE)
                                            of (fetch PUPCONTENTS of PUP))
                                    ((LIST \LEAFOP.WRITE \LEAFOP.TRUNCATE) 
                                                             (* ; "Always important")
                                         T)
                                    (\LEAFOP.CLOSE           (* ; "Closing an output file?")
                                                   (DIRTYABLE X))
                                    NIL)))
              (RETURN X)))
          (SETQ PUP (fetch EPLINK of PUP))
          (GO LP])

(\LEAF.IDLE
  [LAMBDA (SEQUIN)                                       (* ; "Edited 24-May-91 15:08 by jds")

    (* ;; "Called after a suitable timeout with no activity on connection")

    (COND
       [(fetch (SEQUIN LEAFCACHEDFILE) of SEQUIN)
        (ADD.PROCESS (LIST (FUNCTION \LEAF.MAYBE.FLUSH.CACHE)
                           (KWOTE SEQUIN]
       ((for STREAM in (fetch (FDEV OPENFILELST) of (\GETDEVICEFROMNAME
                                                                     (fetch (SEQUIN SEQNAME)
                                                                        of SEQUIN)))
           thereis (EQ (fetch (LEAFSTREAM LEAFCONNECTION) of STREAM)
                           SEQUIN))                          (* ; 
                                                           "Keep activity on this connection")
        (\SEQUIN.CONTROL SEQUIN \SEQUIN.NOOP))
       (T (replace (SEQUIN LEAFCLOSING) of SEQUIN with T)
          (\SEQUIN.CLOSE SEQUIN])

(\LEAF.MAYBE.FLUSH.CACHE
  [LAMBDA (SEQUIN)                                       (* ; "Edited 24-May-91 14:54 by jds")

    (* ;; "Called when leaf connection has been idle a while and there is a file in the cache.  Only flush it if we can get the lock; else try again later.  This keeps this process from hanging (and identical ones accumulating) in the case where the connection is wedged.")

    (if (OBTAIN.MONITORLOCK (fetch (SEQUIN LEAFOPENCLOSELOCK) of SEQUIN)
                   T T)
        then (\LEAF.FLUSH.CACHE SEQUIN])

(\LEAF.WHENCLOSED
  [LAMBDA (SEQUIN FINALSTATE REASON)                     (* ; "Edited 24-May-91 15:12 by jds")
    (PROG ((CODE (COND
                    ((EQ REASON \SS.NOSOCKET)
                     \LEAF.NEVER.OPENED)
                    (T \LEAF.BROKEN.STATUS)))
           PUP DEV)
          (replace (SEQUIN LEAFCACHEDFILE) of SEQUIN with NIL)
                                                             (* ; 
                                                           "Break this potential circular link")
          (COND
             ((fetch (SEQUIN LEAFABORTBUTTONWINDOW) of SEQUIN)
              (CLOSEW (fetch (SEQUIN LEAFABORTBUTTONWINDOW) of SEQUIN))
              (replace (SEQUIN LEAFABORTBUTTONWINDOW) of SEQUIN with NIL)))
          (while (SETQ PUP (\DEQUEUE (fetch (SEQUIN SEQDONEQ) of SEQUIN)))
             do (replace (LEAFPACKET LEAFSTATUS) of PUP with CODE))
          (while (SETQ PUP (\DEQUEUE (fetch (SEQUIN SEQRETRANSMITQ) of SEQUIN)))
             do (replace (LEAFPACKET LEAFSTATUS) of PUP with CODE))
          (replace (SEQUIN SEQINPUTQLENGTH) of SEQUIN with 0)
          (AND (SETQ DEV (\GETDEVICEFROMNAME (fetch (SEQUIN SEQNAME) of SEQUIN)
                                T T))
               (EQ (fetch (PUPFILESERVER PFSLEAFSEQUIN) of (SETQ DEV (fetch DEVICEINFO
                                                                                of DEV)))
                   SEQUIN)
               (replace (PUPFILESERVER PFSLEAFSEQUIN) of DEV with NIL])

(\LEAF.IDLE?
  [LAMBDA (SEQUIN)                                       (* ; "Edited 24-May-91 14:54 by jds")

    (* ;; "Tells SEQUIN process how long to block when it otherwise has nothing to do, i.e.  no packets remain unacked")

    (COND
       ((NEQ (fetch (SEQUIN SEQINPUTQLENGTH) of SEQUIN)
             0)                                              (* ; "Still waiting for something")
        NIL)
       ((fetch (SEQUIN LEAFCACHEDFILE) of SEQUIN)
        \LEAF.CACHETIMEOUT)
       (T                                                    (* ; "For now, wait forever")
          \LEAF.IDLETIMEOUT])
)

(ADDTOVAR NETWORKOSTYPES )



(* ;; "Miscellaneous and error handling")

(DEFINEQ

(\ADDLEAFSTRING
  [LAMBDA (PUP STRING DECODE)                            (* ; "Edited 24-May-91 14:58 by jds")
    (PROG ((PUPBASE (fetch PUPCONTENTS of PUP))
           LEAFLEN STRLEN STRBASE STROFF PUPSTRBASE NEWLENGTH)
          (SETQ LEAFLEN (CEIL (fetch (LEAFDATA LEAFLENGTH) of PUPBASE)
                              BYTESPERWORD))                 (* ; 
                                       "Round Length up to next word--strings must be word-aligned")
          [COND
             ((NULL STRING)
              (SETQ STRLEN 0))
             ((LITATOM STRING)
              (SETQ STRBASE (fetch (LITATOM PNAMEBASE) of STRING))
              (SETQ STROFF 1)
              (SETQ STRLEN (fetch (LITATOM PNAMELENGTH) of STRING)))
             (T (OR (STRINGP STRING)
                    (SETQ STRING (MKSTRING STRING)))
                (SETQ STRBASE (fetch (STRINGP BASE) of STRING))
                (SETQ STROFF (fetch (STRINGP OFFST) of STRING))
                (SETQ STRLEN (fetch (STRINGP LENGTH) of STRING]
          (COND
             ((IGREATERP (SETQ NEWLENGTH (IPLUS LEAFLEN STRLEN BYTESPERWORD))
                     \MAX.PUPLENGTH)
              (ERROR "PUP OVERFLOW" PUP)))
          (\PUTBASE (SETQ PUPSTRBASE (\ADDBASE PUPBASE (FOLDLO LEAFLEN BYTESPERWORD)))
                 0 STRLEN)
          (SETQ PUPSTRBASE (\ADDBASE PUPSTRBASE 1))
          (COND
             ((EQ STRLEN 0))
             [DECODE (for I from 0 to (SUB1 STRLEN)
                        do (\PUTBASEBYTE PUPSTRBASE I (\DECRYPT.PWD.CHAR (\GETBASEBYTE
                                                                              STRBASE
                                                                              (IPLUS I STROFF]
             (T (\MOVEBYTES STRBASE STROFF PUPSTRBASE 0 STRLEN)))
          (replace (LEAFDATA LEAFLENGTH) of PUPBASE with NEWLENGTH])

(\FIXPASSWORD
  [LAMBDA (ERRCODE CONNECTION DIRECTORY)                 (* ; "Edited 24-May-91 14:54 by jds")

    (* ;; "Called when a username or password error occurs.  ERRCODE is the IFS errorcode (name or password error).  Attempts to get new name and/or password for use on CONNECTION.  If DIRECTORY is specified, it is a connect error to that directory")

    (\INTERNAL/GETPASSWORD (fetch (SEQUIN SEQNAME) of CONNECTION)
           (NEQ ERRCODE \IFSERROR.PROTECTION)
           DIRECTORY
           (SELECTC ERRCODE
               (\IFSERROR.PASSWORD 
                    "Incorrect password")
               ((LIST \IFSERROR.USERNAME \IFSERROR.NEED.USERNAME) 
                    "Invalid username")
               (\IFSERROR.CONNECTPASSWORD 
                    "Incorrect connect password")
               (\IFSERROR.CONNECTNAME 
                    "Invalid connect name")
               (\IFSERROR.PROTECTION 
                    "Protection violation")
               (\IFSERROR.NO.LOGIN 
                    "Can't login as files-only directory")
               "Unknown error"])

(\GETLEAFSTRING
  [LAMBDA (ADDR)                                         (* bvm%: "30-MAR-83 17:39")

    (* ;; "Retrieves the IFS string starting at ADDR.  IFS string has length in its first word")

    (PROG ((LEN (\GETBASE ADDR 0)))
          (RETURN (AND (IGREATERP LEN 0)
                       (\GETBASESTRING ADDR 2 LEN])

(\IFSERRORSTRING
  [LAMBDA (CODE FILENAME CONNECTION)                     (* ; "Edited 24-May-91 14:54 by jds")

    (* ;; "Returns the error string associated with IFS error CODE.  FILENAME is the name of the file that caused the error (used for recursion break);  CONNECTION is the leaf connection on which the error occurred")

    (COND
       ((NOT (AND FILENAME (STRING.EQUAL FILENAME \IFSERRORFILENAME)))
        (LET* ([ERR-MSG-STREAM (CAR (NLSETQ (OPENSTREAM (SETQ \IFSERRORFILENAME
                                                         (PACK* '{ (COND
                                                                      (CONNECTION (fetch
                                                                                   (SEQUIN SEQNAME)
                                                                                     of 
                                                                                           CONNECTION
                                                                                   ))
                                                                      (T \CONNECTED.HOST))
                                                                "}<SYSTEM>IFS.ERRORS"))
                                                   'INPUT]
               (ERR-FILE-NAME (FULLNAME ERR-MSG-STREAM))
               (EOL (FCHARACTER (CHARCODE EOL)))
               (START NIL)
               (LEN NIL)
               (RESULT NIL))

              (* ;; "This is a text file containing entries that look like '$$<error code> <error message>' .  Entries can extend over one line.  Entries are sorted by error code, but I don't make use of that knowledge in the brute force procedure below")

              (COND
                 (ERR-MSG-STREAM (SETQ \IFSERRORFILENAME ERR-FILE-NAME)
                                                             (* ; 
                   "In case an error happens while scanning file, update this var to correct value")
                        (PROG1 (COND
                                  ((SETQ START (FFILEPOS (CONCAT EOL "$$" CODE " ")
                                                      ERR-MSG-STREAM 0 NIL NIL T))
                                   (SETQ LEN (IDIFFERENCE (OR (FFILEPOS (CONCAT EOL "$$")
                                                                     ERR-MSG-STREAM START)
                                                              (GETEOFPTR ERR-MSG-STREAM))
                                                    START))  (* ; "Length of entry")
                                   (SETQ RESULT (ALLOCSTRING LEN))
                                   (SETFILEPTR ERR-MSG-STREAM START)
                                   (for I from 1 to LEN do (RPLCHARCODE RESULT I
                                                                                  (\BIN 
                                                                                       ERR-MSG-STREAM
                                                                                        )))
                                   RESULT))
                               (CLOSEF ERR-MSG-STREAM])

(\LEAF.ERROR
  [LAMBDA (PUP FILENAME CONNECTION SENTPUP)   (* ; 
                                                "Edited  2-Nov-92 03:37 by sybalsky:mv:envos")
    (PROG ((DATA (fetch PUPCONTENTS of PUP))
           ERRCODE MSG)
          (RETURN (SELECTC (SETQ ERRCODE (fetch (LEAFERRORDATA LEAFERRORCODE) of DATA))
                      (\IFSERROR.FILE.NOT.FOUND 
                           (LISPERROR "FILE NOT FOUND" FILENAME))
                      (\IFSERROR.MALFORMED 
                           (LISPERROR "BAD FILE NAME" FILENAME))
                      (\IFSERROR.ALLOCATION 
                           (LISPERROR "FILE SYSTEM RESOURCES EXCEEDED" FILENAME))
                      (\IFSERROR.BAD.HANDLE 
                           (ERROR "Leaf Error: Bad Handle.
This shouldn't happen: Lisp and the server have different ideas about which file they are talking about.  All operations to this file are now suspended.  See a wizard if possible."
                                  (fetch (STREAM FULLFILENAME) of FILENAME)))
                      (PROGN [SETQ MSG (SELECTC ERRCODE
                                           (\IFSERROR.BUSY 
                                                "File busy")
                                           (\IFS.ERROR.BROKEN.LEAF 
                                                
                   "Leaf Broken--a file you had open was accessed by another user while it was idle.")
                                           (CONCAT "Leaf error: "
                                                  (OR [AND (IGREATERP (fetch PUPLENGTH
                                                                         of PUP)
                                                                  \SHORT.ERROR.PUPLEN)
                                                           (\GETLEAFSTRING
                                                            (LOCF (fetch (LEAFERRORDATA 
                                                                                    LEAFERRORMSG)
                                                                     of DATA]
                                                      (\IFSERRORSTRING ERRCODE FILENAME 
                                                             CONNECTION)
                                                      ERRCODE]
                             (COND
                                ((EQ (fetch (LEAFERRORDATA LEAFERROROPCODE) of DATA)
                                     \LEAFOP.OPEN)
                                 (printout PROMPTWINDOW T MSG T)
                                 (LISPERROR "FILE WON'T OPEN" FILENAME))
                                (T (ERROR MSG FILENAME])

(\LEAF.DIRECTORYNAMEONLY
  [LAMBDA (FILENAME)                                     (* bvm%: "19-NOV-81 11:34")
    (PROG ((DIR (FILENAMEFIELD FILENAME 'DIRECTORY))
           N)
          (RETURN (COND
                     ((SETQ N (STRPOS '> DIR))
                      (SUBATOM DIR 1 (SUB1 N)))
                     (T DIR])

(GETHOSTINFO
  [LAMBDA (HOST ATTRIBUTE)                             (* ; "Edited 10-Oct-90 17:39 by gadener")
    (SETQ HOST (MKATOM (U-CASE HOST)))
    (PROG (NSFLG (INFO (ASSOC HOST NETWORKOSTYPES))
                 VAL)
          (COND
             (INFO                                           (* ; " already know about this host")
                   )
             [(SETQ NSFLG (STRPOS '%: HOST))                 (* ; " default NS information")
              (SETQ INFO '(NIL . NS]
             [(AND (BOUNDP \IPFLG)
                   \IPFLG)                                   (* ; "Check for IP info")
              (SETQ HOST (\DOMAIN.NAME.QUALIFY.FULLY HOST))
              (SETQ INFO (CONS NIL (fetch (HOSTS.TXT.ENTRY HTE.OS.TYPE) of (GETHASH HOST 
                                                                                        \IP.HOSTNAMES
                                                                                          ]
             [(AND (NEQ HOST (SETQ HOST (CANONICAL.HOSTNAME HOST)))
                                                             (* ; "Check for NS and PUP info")
                   (SETQ INFO (ASSOC HOST NETWORKOSTYPES]
             (DEFAULT.OSTYPE (SETQ INFO (CONS NIL DEFAULT.OSTYPE)))
             (T (RETURN)))
          (RETURN (OR (SELECTQ ATTRIBUTE
                          ((OS OSTYPE)                       (* ; " get OS type")
                               (COND
                                  ((LISTP (CDR INFO))
                                   (LISTGET (CDR INFO)
                                          'OSTYPE))
                                  (T (CDR INFO))))
                          (LOGINFO [COND
                                      ((SETQ VAL (ASSOC HOST NETWORKLOGINFO))
                                       (CDR VAL))
                                      (T (CDR (ASSOC (COND
                                                        ((LISTP (CDR INFO))
                                                         (LISTGET (CDR INFO)
                                                                'OSTYPE))
                                                        (T (CDR INFO)))
                                                     NETWORKLOGINFO])
                          (PROTOCOLS (COND
                                        ((LITATOM (CDR INFO))
                                         (SELECTQ (CDR INFO)
                                             (IFS '(LEAF PUPFTP CHAT LOOKUPFILE))
                                             NIL))))
                          NIL)
                      (AND (LISTP (CDR INFO))
                           (LISTGET (CDR INFO)
                                  ATTRIBUTE])

(GETOSTYPE
  [LAMBDA (HOST)                                         (* bvm%: "31-OCT-83 17:08")
    (GETHOSTINFO HOST 'OSTYPE])

(EXPANDING-PAGEFULLFN
  [LAMBDA (W)                                            (* ; "Edited 14-Apr-87 22:25 by bvm:")

    (* ;; "Hack for getting a window large enough to hold everything you want to display without having to make it big enough in the first place.  This function is intended to be the PAGEFULLFN on the window that is your process's ttydisplaystream.  As soon as the window fills up, it grows the window on the bottom to show more.  The number of lines it expands by is given by the window's EXPANDING-INCREMENT property, defaults to 4.")

    (LET ((OLDREGION (WINDOWREGION W))
          [INCREMENT (TIMES (OR (WINDOWPROP W 'EXPANDING-INCREMENT)
                                4)
                            (- (DSPLINEFEED NIL W]
          (CURRENTHEIGHT \#DISPLAYLINES))
         [SHAPEW W (create REGION using OLDREGION HEIGHT _ (+ INCREMENT (fetch
                                                                                 (REGION HEIGHT)
                                                                                   of OLDREGION))
                                            BOTTOM _ (IMAX 0 (- (fetch (REGION BOTTOM)
                                                                   of OLDREGION)
                                                                INCREMENT]

         (* ;; "The SHAPEW resets height parameters as if window cleared.  We want display to believe that the pagefullfn never happened, so that we can expand again the next time we hit bottom.")

         (SETQ \CURRENTDISPLAYLINE CURRENTHEIGHT])
)

(RPAQQ DEFAULT.OSTYPE IFS)
(DECLARE%: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS DEFAULT.OSTYPE)
)



(* ;; "LookUpFile stuff")

(DEFINEQ

(\IFS.LOOKUPFILE
  [LAMBDA (NAME RECOG ATTRIBUTE DEVINFO)                 (* ; "Edited 24-May-91 15:12 by jds")

(* ;;; "Attempt to use the LookupFile protocol to get full filename")

    (PROG ((RESULT '?)
           (HOSTNAME (fetch (PUPFILESERVER PFSNAME) of DEVINFO))
           (OSTYPE (fetch (PUPFILESERVER PFSOSTYPE) of DEVINFO))
           REMOTENAME SEMI NAME/PASS START DOT ROOTNAME INFO IPUP OPUP PUPSOC DIREND LOCK)
          (COND
             ([OR (NEQ (NTHCHARCODE NAME 1)
                       (CHARCODE {))
                  (NOT (SETQ START (STRPOS '} NAME 2]
              (RETURN)))
          (COND
             ((NOT (SETQ LOCK (fetch (PUPFILESERVER PFSLOOKUPFILELOCK) of DEVINFO)))
                                                             (* ; "First time to do this")
              (replace (PUPFILESERVER PFSLOOKUPFILESOCKET) of DEVINFO with (SETQ PUPSOC
                                                                                        (
                                                                                        OPENPUPSOCKET
                                                                                         )))
              (replace (PUPFILESERVER PFSLOOKUPFILELOCK) of DEVINFO with (SETQ LOCK
                                                                                      (
                                                                                   CREATE.MONITORLOCK
                                                                                       "LookUpFile"))
                     )
              (replace (PUPFILESERVER PFSLOOKUPFAILCNT) of DEVINFO with 0))
             ((NOT (SETQ PUPSOC (fetch (PUPFILESERVER PFSLOOKUPFILESOCKET) of DEVINFO)))
              (RETURN RESULT)))
          [SETQ ROOTNAME (SUBSTRING NAME (ADD1 START)
                                (COND
                                   ([SETQ SEMI (OR (STRPOS '; NAME (ADD1 START))
                                                   (STRPOS '! NAME (ADD1 START]
                                    (PROG1 (SUB1 SEMI)
                                        (COND
                                           ((EQ SEMI (NCHARS NAME))
                                                             (* ; "Not really a version there")
                                            (SETQ SEMI NIL))))]
          (while (SETQ DOT (STRPOS '> ROOTNAME DIREND)) do (SETQ DIREND (ADD1 DOT)))
          [COND
             ((NOT DIREND)
              (SETQ DIREND (IMINUS (NCHARS ROOTNAME)))
              (SETQ ROOTNAME (CONCAT '< (CAR (\INTERNAL/GETPASSWORD HOSTNAME))
                                    '> ROOTNAME]
          (COND
             [(SETQ DOT (STRPOS '%. ROOTNAME DIREND))        (* ; 
                          "Name ends in dot, but is only %"extensionless%" if the dot isn't quoted")
              (SETQ DOT (AND (EQ DOT (NCHARS ROOTNAME))
                             (NEQ (NTHCHARCODE ROOTNAME (SUB1 DOT))
                                  (CHARCODE "'"]
             (T (SETQ ROOTNAME (CONCAT ROOTNAME '%.))
                (SETQ DOT T)))                               (* ; 
                  "DOT now T if filename is extensionless.  ROOTNAME is everything but the version")
          [SETQ REMOTENAME (COND
                              [(EQ (SETQ OSTYPE (GETHOSTINFO HOSTNAME 'OSTYPE))
                                   'TENEX)                   (* ; 
                                                           "Our filenames are already Tenex style")
                               (COND
                                  ((OR SEMI (NEQ RECOG 'OLDEST))
                                   ROOTNAME)
                                  (T (CONCAT ROOTNAME ";-2"]
                              [SEMI                          (* ; "Use ! for version delimiter")
                                    (CONCAT (COND
                                               (DOT (SUBSTRING ROOTNAME 1 -2))
                                               (T ROOTNAME))
                                           (COND
                                              ((EQ OSTYPE 'TOPS20)
                                               '%.)
                                              (T '!))
                                           (SUBSTRING NAME (ADD1 SEMI]
                              ((EQ OSTYPE 'TOPS20)
                               (COND
                                  ((EQ RECOG 'OLDEST)
                                   (CONCAT ROOTNAME ".-2"))
                                  (T ROOTNAME)))
                              (T (SETQ REMOTENAME (COND
                                                     (DOT (SUBSTRING ROOTNAME 1 -2))
                                                     (T ROOTNAME)))
                                 (COND
                                    ((EQ RECOG 'OLDEST)
                                     (CONCAT REMOTENAME "!L"))
                                    (T REMOTENAME]
          (WITH.MONITOR LOCK
              (SETUPPUP (SETQ OPUP (ALLOCATE.PUP))
                     HOSTNAME \SOCKET.LOOKUPFILE \PT.LOOKUPFILE NIL PUPSOC)
              (\PUTPUPSTRING OPUP (if (STRPOS "'" REMOTENAME)
                                      then (\LEAF.STRIP.QUOTES REMOTENAME)
                                    else REMOTENAME))
              [to \MAXETHERTRIES when (SETQ IPUP (EXCHANGEPUPS PUPSOC OPUP NIL T))
                 do (SELECTC (fetch PUPTYPE of IPUP)
                            (\PT.LOOKUPFILEREPLY 
                                 [RETURN (SETQ RESULT (SELECTQ ATTRIBUTE
                                                          ((NAME NIL) 
                                                               (SETQ REMOTENAME
                                                                (CONCAT '{ HOSTNAME '} ROOTNAME
                                                                       ';
                                                                       (fetch (LOOKUPFILEDATA
                                                                                   LOOKUPVERSION)
                                                                          of IPUP)))
                                                               (if *UPPER-CASE-FILE-NAMES*
                                                                   then (MKATOM (U-CASE 
                                                                                           REMOTENAME
                                                                                           ))
                                                                 else REMOTENAME))
                                                          (CREATIONDATE (GDATE
                                                                         (ALTO.TO.LISP.DATE
                                                                          (fetch (LOOKUPFILEDATA
                                                                                      
                                                                                   LOOKUPCREATIONDATE
                                                                                      ) of IPUP))
                                                                         ))
                                                          (ICREATIONDATE (ALTO.TO.LISP.DATE
                                                                          (fetch (LOOKUPFILEDATA
                                                                                      
                                                                                   LOOKUPCREATIONDATE
                                                                                      ) of IPUP)))
                                                          (LENGTH (fetch (LOOKUPFILEDATA 
                                                                                    LOOKUPLENGTH)
                                                                     of IPUP))
                                                          (\ILLEGAL.ARG ATTRIBUTE])
                            (\PT.LOOKUPFILEERROR             (* ; "No such file")
                                 (RETURN (SETQ RESULT NIL)))
                            (\PT.ERROR (COND
                                          ((EQ (fetch ERRORPUPCODE of IPUP)
                                               \PUPE.NOSOCKET)
                                                             (* ; "No such socket")
                                           (AND PUPTRACEFLG (PRINTERRORPUP IPUP PUPTRACEFILE))
                                           (replace (PUPFILESERVER PFSLOOKUPFILESOCKET)
                                              of DEVINFO with NIL)
                                           (CLOSEPUPSOCKET PUPSOC)
                                           (RETURN))))
                            NIL)
                       (RELEASE.PUP IPUP) finally (SETQ IPUP)
                                                (COND
                                                   (PUPTRACEFLG "LookupFile timed out" T))
                                                (COND
                                                   ((AND (fetch (PUPFILESERVER PFSLOOKUPFAILCNT)
                                                            of DEVINFO)
                                                         (> (add (fetch (PUPFILESERVER 
                                                                                     PFSLOOKUPFAILCNT
                                                                                       ) of
                                                                                         DEVINFO)
                                                                   1)
                                                            4))
                                                    (replace (PUPFILESERVER PFSLOOKUPFILESOCKET)
                                                       of DEVINFO with NIL)
                                                    (CLOSEPUPSOCKET PUPSOC]
              (AND IPUP (RELEASE.PUP IPUP))
              (COND
                 ((NEQ RESULT '?)
                  (replace (PUPFILESERVER PFSLOOKUPFAILCNT) of DEVINFO with NIL))))
          (RETURN RESULT])
)
(DECLARE%: EVAL@COMPILE DONTCOPY 

(RPAQQ LOOKUPFILECOMS ((CONSTANTS \PT.LOOKUPFILE \PT.LOOKUPFILEREPLY \PT.LOOKUPFILEERROR 
                              \SOCKET.LOOKUPFILE)
                       (RECORDS LOOKUPFILEDATA)
                       (GLOBALVARS \LOOKUPFILE.HOSTINFO)))
(DECLARE%: EVAL@COMPILE 

(RPAQQ \PT.LOOKUPFILE 200Q)

(RPAQQ \PT.LOOKUPFILEREPLY 201Q)

(RPAQQ \PT.LOOKUPFILEERROR 202Q)

(RPAQQ \SOCKET.LOOKUPFILE 61Q)


(CONSTANTS \PT.LOOKUPFILE \PT.LOOKUPFILEREPLY \PT.LOOKUPFILEERROR \SOCKET.LOOKUPFILE)
)
(DECLARE%: EVAL@COMPILE

(ACCESSFNS LOOKUPFILEDATA ((LOOKUPFILEBASE (fetch PUPCONTENTS of DATUM)))
                          (BLOCKRECORD LOOKUPFILEBASE ((LOOKUPVERSION WORD)
                                                       (LOOKUPCREATIONDATE FIXP)
                                                       (LOOKUPLENGTH FIXP))))
)
(DECLARE%: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS \LOOKUPFILE.HOSTINFO)
)
)
(DEFINEQ

(\LEAFINIT
  [LAMBDA NIL                                            (* bvm%: "12-SEP-83 15:39")
    (SETQ \LEAFCONNECTIONLOCK (CREATE.MONITORLOCK 'LEAF))
    (\DEFINEDEVICE NIL (create FDEV
                              DEVICENAME _ 'LEAF
                              RESETABLE _ T
                              RANDOMACCESSP _ T
                              PAGEMAPPED _ T
                              HOSTNAMEP _ (FUNCTION \LEAF.DEVICEP)
                              EVENTFN _ (FUNCTION NILL)
                              DELETEFILE _ (FUNCTION \ILLEGAL.DEVICEOP)
                              GETFILEINFO _ (FUNCTION \ILLEGAL.DEVICEOP)
                              OPENFILE _ (FUNCTION \ILLEGAL.DEVICEOP)
                              SETFILEINFO _ (FUNCTION \ILLEGAL.DEVICEOP)
                              GETFILENAME _ (FUNCTION \ILLEGAL.DEVICEOP)
                              GENERATEFILES _ (FUNCTION \ILLEGAL.DEVICEOP)
                              DIRECTORYNAMEP _ (FUNCTION \ILLEGAL.DEVICEOP)
                              RENAMEFILE _ (FUNCTION \ILLEGAL.DEVICEOP])
)
(DECLARE%: DONTEVAL@LOAD 

(\LEAFINIT)
)
(DEFINEQ

(PRINTLEAF
  [LAMBDA (PUP)                                          (* ; "Edited 24-May-91 14:59 by jds")

(* ;;; "Prints a LEAF pup.  Called from PRINTPUP")

    (PROG ((LENGTH (IDIFFERENCE (fetch PUPLENGTH of PUP)
                          \PUPOVLEN))
           DATA OP START HI LO MACRO NBYTES)
          (COND
             ((EQ (fetch (SEQUINPACKET SEQCONTROL) of PUP)
                  \SEQUIN.DATA)
              (printout NIL "SequinData"))
             (T (printout NIL "SequinOp = ")
                (PRINTCONSTANT (fetch (SEQUINPACKET SEQCONTROL) of PUP)
                       SEQUINOPS NIL "\SEQUIN.")))
          (printout NIL ", alloc = " .P2 (fetch (SEQUINPACKET ALLOCATE) of PUP)
                 ", recv = " .P2 (fetch (SEQUINPACKET RECEIVESEQ) of PUP)
                 ", send = " .P2 (fetch (SEQUINPACKET SENDSEQ) of PUP)
                 T)
          [COND
             ((IGREATERP LENGTH 0)
              (SETQ DATA (fetch PUPCONTENTS of PUP))
              (printout NIL "Leaf")
              (COND
                 ((SETQ OP (SELECTC (fetch (LEAFDATA LEAFOPCODE) of DATA)
                               (\LEAFOP.OPEN "Open")
                               (\LEAFOP.CLOSE "Close")
                               (\LEAFOP.READ "Read")
                               (\LEAFOP.WRITE "Write")
                               (\LEAFOP.ERROR "Error")
                               NIL))
                  (printout NIL OP))
                 (T (printout NIL "Op = ")
                    (PRINTCONSTANT (fetch (LEAFDATA LEAFOPCODE) of DATA)
                           LEAFOPCODES NIL "\LEAFOP.")))
              (COND
                 ((EQ (fetch (LEAFDATA ANSWERBIT) of DATA)
                      1)
                  (printout NIL " (ans)")))
              (COND
                 ((AND (EQ (fetch (LEAFDATA OPCODE) of DATA)
                           \LEAFOP.WRITE)
                       (EQ (fetch (LEAFDATA EOFBIT) of DATA)
                           1))
                  (printout NIL " (eof)")))
              (COND
                 ((NEQ (fetch (LEAFDATA LEAFLENGTH) of DATA)
                       LENGTH)
                  (printout NIL ", length = " .P2 (fetch (LEAFDATA LEAFLENGTH) of DATA)
                         " [but Pup Length = header + " .P2 LENGTH "!]")))
              (printout NIL ", Handle = " .P2 (fetch (LEAFDATA HANDLE) of DATA))
              (COND
                 ([AND (IGREATERP LENGTH (SETQ START 4))
                       (SETQ MACRO
                        (SELECTC (fetch (LEAFDATA LEAFOPCODE) of DATA)
                            (\LEAFOP.OPEN [COND
                                             ((EQ (fetch (LEAFDATA ANSWERBIT) of DATA)
                                                  0)
                                              '("Mode: " WORDS 6 " Login: " CHARS IFSSTRING ; BYTES 
                                                      IFSSTRING " Connect: " CHARS IFSSTRING ; BYTES
                                                      IFSSTRING " File: " CHARS IFSSTRING))
                                             (T '("FileLength = " INTEGER 10Q |...|])
                            (\LEAFOP.RESET '("Login: " CHARS IFSSTRING BYTES))
                            ((LIST \LEAFOP.READ \LEAFOP.WRITE) 
                                 (SETQ HI (SIGNED (fetch (LEAFDATA JUSTHIADDR) of DATA)
                                                 13Q))
                                 (SETQ LO (fetch (LEAFDATA LOADDR) of DATA))
                                 (SETQ NBYTES (fetch (LEAFDATA DATALENGTH) of DATA))
                                 [COND
                                    [(AND (EVENP NBYTES BYTESPERPAGE)
                                          (IGEQ HI 0))
                                     [printout NIL ", Page " .P2 (SETQ LO (IPLUS (FOLDLO LO 
                                                                                        BYTESPERPAGE)
                                                                                 (LLSH HI 7]
                                     (COND
                                        ((IGREATERP NBYTES BYTESPERPAGE)
                                         (printout NIL " thru " .P2 (IPLUS LO (FOLDLO NBYTES 
                                                                                     BYTESPERPAGE)
                                                                           -1]
                                    (T (printout NIL T .P2 NBYTES " bytes from " .P2
                                              (\MAKENUMBER (UNSIGNED HI BITSPERWORD)
                                                     LO]
                                 [COND
                                    ((SELECTC (fetch (LEAFDATA LEAFOPCODE) of DATA)
                                         (\LEAFOP.WRITE (EQ (fetch (LEAFDATA ANSWERBIT)
                                                               of DATA)
                                                            0))
                                         (IGREATERP LENGTH 12Q))
                                     (SETQ START 12Q)
                                     '("Data: " CHARS 24Q |...|])
                            (\LEAFOP.ERROR '("Error op: " WORDS 6 "Error handle: " 10Q IFSSTRING))
                            '(BYTES]
                  (TERPRI)
                  (PRINTPACKETDATA DATA START MACRO LENGTH))
                 (T (TERPRI]
          (TERPRI))
    PUP])
)

(ADDTOVAR PUPPRINTMACROS (260Q . PRINTLEAF))

(RPAQ? LEAFDEBUGFLG )

(RPAQ? LEAFABORTREGION '(641Q 1150Q 617Q 300Q))

(RPAQ? \MAXLEAFTRIES 4)

(RPAQ? NOFILEPROPERROR )

(RPAQ? DEFAULTFILETYPE 'TEXT)

(RPAQ? \SOCKET.LEAF 43Q)

(RPAQ? \SEQUIN.TIMEOUTMAX 23420Q)

(RPAQ? \LEAF.IDLETIMEOUT 6673500Q)

(RPAQ? \LEAF.CACHETIMEOUT 257620Q)

(RPAQ? \LEAF.MAXCACHE 12Q)

(RPAQ? \LEAF.RECOVERY.TIMEOUT 2223700Q)

(RPAQ? \LEAF.MAXLOOKAHEAD 4)

(RPAQ? \FTPAVAILABLE )

(RPAQ? UNIXFTPFLG )

(RPAQ? NONLEAFHOSTS )

(RPAQ? *UPPER-CASE-FILE-NAMES* T)
(DECLARE%: EVAL@COMPILE DONTCOPY 

(RPAQQ LEAFCOMPILETIMECOMS
       ((RECORDS LEAFDATA LEAFERRORDATA LEAFPARAMSDATA LEAFPACKET LEAFINFOBLOCK LEAFSTREAM LEAFDEVICE
               PUPFILESERVER)
        (MACROS .NAMEORSTREAM. .PAGE.IS.AFTER.EOF. INCLEAFSTAT)
        (CONSTANTS * LEAFOPCODES)
        (CONSTANTS * IFSERRORS)
        (CONSTANTS (\PT.LEAF 260Q)
               (\PT.ERROR 4)
               (\LEAFOP.ANSWERBIT 2000Q)
               (\LEAF.READBIT 100000Q)
               (\LEAF.WRITEBIT 40000Q)
               (\LEAF.EXTENDBIT 20000Q)
               (\LEAF.MULTIBIT 10000Q)
               (\LEAF.CREATEBIT 4000Q)
               (\LEAF.DEFAULT.LOWEST 200Q)
               (\LEAF.DEFAULT.HIGHEST 400Q)
               (\LEAF.DEFAULT.NEXT 600Q)
               (\LEAF.EXPLICIT.ANY 3000Q)
               (\LEAF.EXPLICIT.OLD 1000Q)
               (\LEAF.EXPLICIT.NEXT.OR.OLD 2000Q)
               (\LEN.RESETLEAF 4)
               (\LEN.LEAFPARAMS 10Q)
               (\LEN.NOOPREQUEST 2)
               (\LEN.OPENREQUEST 6)
               (\LEN.FILEREQUEST 12Q)
               (\LEN.CLOSEREQUEST 4)
               (\LEN.READANSWER 12Q)
               (\OPCODE.SHIFT 13Q)
               (\LEN.CLOSEREQUEST 4)
               (\MAXLEN.FILENAME 144Q)
               (\OFFSET.FILENAME (TIMES 2 400Q))
               (\BYTES.PER.TRIDENT.PAGE 4000Q)
               (\LEN.DATE 4)
               (\LEAFMODE.DONTEXTEND 2)
               (\LEN.FILETYPE&SIZE 4)
               (\OFFSET.FILETYPE 1250Q)
               (\OFFSET.BACKUPDATE 1244Q)
               (\OFFSET.AUTHOR 1174Q)
               (\LEN.AUTHOR 50Q)
               (\SHORT.ERROR.PUPLEN 36Q)
               (\LEAF.GOODSTATUS 177776Q)
               (\LF.ALLOWERRORS 2)
               (\LF.WANTANSWER 1)
               (\LEAF.BROKEN.STATUS 177771Q)
               (\LEAF.NEVER.OPENED 177773Q))
        (CONSTANTS (\FT.TEXT 1)
               (\FT.BINARY 2)
               (\FT.UNKNOWN 0))
        (LOCALVARS . T)
        (GLOBALVARS \LEAFDEVICE \SOCKET.LEAF LEAFDEBUGFLG PUPTRACEFLG NOFILEPROPERROR NETWORKOSTYPES
               LEAFOPCODES SEQUINOPS DEFAULTFILETYPE \LEAF.IDLETIMEOUT \LEAF.CACHETIMEOUT 
               \LEAF.MAXLOOKAHEAD \LEAF.MAXCACHE \LEAFCONNECTIONLOCK \FTPAVAILABLE UNIXFTPFLG 
               \SEQUIN.TIMEOUTMAX LEAFABORTREGION \MAXLEAFTRIES \LEAF.RECOVERY.TIMEOUT NONLEAFHOSTS 
               \FTPFDEV)))
(DECLARE%: EVAL@COMPILE

(BLOCKRECORD LEAFDATA ((OPWORD WORD)
                       (HANDLE WORD)
                       (FILEADDRESS FIXP)
                       (DATALENGTH WORD)
                       (LEAFFIRSTDATAWORD WORD))             (* ; 
                                                          "Format of typical file operation request.")
                      (BLOCKRECORD LEAFDATA ((LEAFOPCODE BITS 5)
                                             (ANSWERBIT BITS 1)
                                             (LEAFLENGTH BITS 12Q)
                                             (NIL WORD)
                                             (READWRITEMODE BITS 2)
                                             (EOFBIT BITS 1)
                                             (NIL BITS 2)
                                             (JUSTHIADDR BITS 13Q)
                                             (LOADDR WORD))  (* ; 
                                                             "Details of the file address format")
                             (SYNONYM LEAFOPCODE (OPCODE)))
                      (BLOCKRECORD LEAFDATA ((NIL 2 WORD)
                                             (SIGNEXTEND BITS 5)
                                             (NIL BITS 33Q)) (* ; "more details")
                             )
                      (BLOCKRECORD LEAFDATA ((NIL 2 WORD)
                                             (OPENMODE WORD))(* ; "format of OPEN file request")
                             )
                      (BLOCKRECORD LEAFDATA ((NIL 5 WORD)
                                             (LEAFFILETYPE WORD)
                                             (LEAFBYTESIZE WORD))
                                                             (* ; "For accessing the file's TYPE")
                             )
                      (BLOCKRECORD LEAFDATA ((NIL 5 WORD)
                                             (LEAFFILEDATE FIXP))
                                                             (* ; 
                                                      "Format of SETFILEINFO of CREATIONDATE request")
                             ))

(BLOCKRECORD LEAFERRORDATA ((NIL WORD)
                            (LEAFERRORCODE WORD)             (* ; "Error subcode in ERROR leafop")
                            (LEAFERROROPCODE BITS 5)         (* ; 
                                                  "The OPCODE in the Leaf packet provoking the error")
                            (NIL BITS 13Q)
                            (LEAFERRORHANDLE WORD)           (* ; "The handle in the provoking op")
                            (LEAFERRORMSG WORD)              (* ; "Actually IFSSTRING starting here")
                            ))

(BLOCKRECORD LEAFPARAMSDATA ((NIL WORD)
                             (LEAFPMAXDATALENGTH WORD)
                             (LEAFPLOCKTIMEOUT WORD)         (* ; 
                                                           "File Lock timeout, in units of 5 seconds")
                             (LEAFPCONNTIMEOUT WORD)         (* ; 
                                                             "Overall connection timeout, same units")
                             ))

(ACCESSFNS LEAFPACKET ((LEAFSTATUS (fetch EPUSERFIELD of DATUM)
                              (replace EPUSERFIELD of DATUM with NEWVALUE))
                       (LEAFFLAGS (fetch EPFLAGS of DATUM)
                              (replace EPFLAGS of DATUM with NEWVALUE))
                       (LEAFANSWERWANTED (NEQ (LOGAND (fetch EPFLAGS of DATUM)
                                                     \LF.WANTANSWER)
                                              0))
                       (LEAFALLOWERRORS (NEQ (LOGAND (fetch EPFLAGS of DATUM)
                                                    \LF.ALLOWERRORS)
                                             0))))

(BLOCKRECORD LEAFINFOBLOCK ((LFCREATIONDATE FIXP)
                            (LFWRITEDATE FIXP)
                            (LFREADDATE FIXP))               (* ; "just like leader page")
                           (BLOCKRECORD LEAFINFOBLOCK ((HICREATE WORD)
                                                       (LOCREATE WORD)
                                                       (HIWRITE WORD)
                                                       (LOWRITE WORD)
                                                       (HIREAD WORD)
                                                       (LOREAD WORD))
                                                             (* ; "for VALIDATION use")
                                  )
                           (CREATE (\ALLOCBLOCK 3)))

(ACCESSFNS LEAFSTREAM ((LEAFCONNECTION (fetch F1 of DATUM)
                              (replace F1 of DATUM with NEWVALUE))
                       (LEAFHANDLE (fetch F2 of DATUM)
                              (replace F2 of DATUM with NEWVALUE))
                       (LEAFPAGECACHE (fetch F3 of DATUM)
                              (replace F3 of DATUM with NEWVALUE))
                       (LEAFINFO (fetch F4 of DATUM)
                              (replace F4 of DATUM with NEWVALUE))
                       (LEAFREALLYOPEN (fetch F5 of DATUM)
                              (replace F5 of DATUM with NEWVALUE))
                       (LEAFCACHECNT (fetch FW6 of DATUM)
                              (replace FW6 of DATUM with NEWVALUE))
                       (LEAFERRORCNT (fetch FW7 of DATUM)
                              (replace FW7 of DATUM with NEWVALUE))))

(ACCESSFNS LEAFDEVICE ((PUPFILESERVER (fetch DEVICEINFO of DATUM)
                              (replace DEVICEINFO of DATUM with NEWVALUE))))

(DATATYPE PUPFILESERVER (
                         (* ;; "Info common to various pup protocols used on a file server, independent of whether a connection is now open")

                         (NIL BYTE)
                         (PFSNAME POINTER)
                         (PFSADDRESS POINTER)                (* ; "Pup address")
                         (PFSOSTYPE POINTER)
                         (PFSLEAFFLG POINTER)                (* ; 
                                                "Indicates something about whether LEAF is available")
                         (PFSLEAFSEQUIN POINTER)             (* ; 
                                                         "Pointer to SEQUIN for open leaf connection")
                         (PFSLEAFTIMER POINTER)              (* ; "Timeout for handling dead servers")
                         (PFSLOOKUPFILESOCKET POINTER)       (* ; 
                                                             "The Pup socket for LookupFile requests")
                         (PFSLOOKUPFILELOCK POINTER)         (* ; "Lock to secure it")
                         (PFSLOOKUPFAILCNT POINTER)          (* ; 
                                                      "Counter used until we know the service exists")
                         (PFSKNOWNDIRS POINTER)              (* ; 
                               "List of directories known to exist on this host (for DIRECTORYNAMEP)")
                         (NIL POINTER)))
)

(/DECLAREDATATYPE 'PUPFILESERVER '(BYTE POINTER POINTER POINTER POINTER POINTER POINTER POINTER 
                                        POINTER POINTER POINTER POINTER)
       '((PUPFILESERVER 0 (BITS . 7))
         (PUPFILESERVER 2 POINTER)
         (PUPFILESERVER 4 POINTER)
         (PUPFILESERVER 6 POINTER)
         (PUPFILESERVER 10Q POINTER)
         (PUPFILESERVER 12Q POINTER)
         (PUPFILESERVER 14Q POINTER)
         (PUPFILESERVER 16Q POINTER)
         (PUPFILESERVER 20Q POINTER)
         (PUPFILESERVER 22Q POINTER)
         (PUPFILESERVER 24Q POINTER)
         (PUPFILESERVER 26Q POINTER))
       '30Q)
(DECLARE%: EVAL@COMPILE 

(PUTPROPS .NAMEORSTREAM. MACRO (OPENLAMBDA (FILENAME)
                                 (COND
                                    ((type? STREAM FILENAME)
                                     (fetch FULLFILENAME of FILENAME))
                                    (T FILENAME))))

(PUTPROPS .PAGE.IS.AFTER.EOF. MACRO [OPENLAMBDA (STREAM PAGE#)
                                      (AND (IGEQ PAGE# (fetch EPAGE of STREAM))
                                           (OR (NOT (IEQP (fetch EPAGE of STREAM)
                                                          PAGE#))
                                               (EQ (fetch EOFFSET of STREAM)
                                                   0])

(PUTPROPS INCLEAFSTAT MACRO ((X)
                             (change X (IPLUS16 DATUM 1))))
)

(RPAQQ LEAFOPCODES
       ((\LEAFOP.ERROR 0)
        (\LEAFOP.OPEN 1)
        (\LEAFOP.CLOSE 2)
        (\LEAFOP.DELETE 3)
        (\LEAFOP.LENGTH 4)
        (\LEAFOP.TRUNCATE 5)
        (\LEAFOP.READ 6)
        (\LEAFOP.WRITE 7)
        (\LEAFOP.RESET 10Q)
        (\LEAFOP.NOOP 11Q)
        (\LEAFOP.TELNET 12Q)
        (\LEAFOP.PARAMS 13Q)))
(DECLARE%: EVAL@COMPILE 

(RPAQQ \LEAFOP.ERROR 0)

(RPAQQ \LEAFOP.OPEN 1)

(RPAQQ \LEAFOP.CLOSE 2)

(RPAQQ \LEAFOP.DELETE 3)

(RPAQQ \LEAFOP.LENGTH 4)

(RPAQQ \LEAFOP.TRUNCATE 5)

(RPAQQ \LEAFOP.READ 6)

(RPAQQ \LEAFOP.WRITE 7)

(RPAQQ \LEAFOP.RESET 10Q)

(RPAQQ \LEAFOP.NOOP 11Q)

(RPAQQ \LEAFOP.TELNET 12Q)

(RPAQQ \LEAFOP.PARAMS 13Q)


(CONSTANTS (\LEAFOP.ERROR 0)
       (\LEAFOP.OPEN 1)
       (\LEAFOP.CLOSE 2)
       (\LEAFOP.DELETE 3)
       (\LEAFOP.LENGTH 4)
       (\LEAFOP.TRUNCATE 5)
       (\LEAFOP.READ 6)
       (\LEAFOP.WRITE 7)
       (\LEAFOP.RESET 10Q)
       (\LEAFOP.NOOP 11Q)
       (\LEAFOP.TELNET 12Q)
       (\LEAFOP.PARAMS 13Q))
)

(RPAQQ IFSERRORS
       ((\IFSERROR.BAD.CHARACTER 312Q)
        (\IFSERROR.MALFORMED '(311Q 312Q))
        (\IFSERROR.FILE.NOT.FOUND 317Q)
        (\IFSERROR.PROTECTION 320Q)
        (\IFSERROR.BUSY 321Q)
        (\IFSERROR.INVALID.DIRECTORY 322Q)
        (\IFSERROR.ALLOCATION 323Q)
        (\IFSERROR.USERNAME 330Q)
        (\IFSERROR.PASSWORD 331Q)
        (\IFSERROR.NO.LOGIN 332Q)
        (\PASSWORD.ERRORS '(330Q 331Q 332Q 337Q))
        (\IFSERROR.CONNECTNAME 333Q)
        (\IFSERROR.CONNECTPASSWORD 334Q)
        (\CONNECT.PASSWORD.ERRORS '(333Q 334Q))
        (\IFSERROR.NEED.USERNAME 337Q)
        (\IFS.ERROR.BROKEN.LEAF 1751Q)
        (\IFSERROR.BAD.HANDLE 1763Q)))
(DECLARE%: EVAL@COMPILE 

(RPAQQ \IFSERROR.BAD.CHARACTER 312Q)

(RPAQQ \IFSERROR.MALFORMED (311Q 312Q))

(RPAQQ \IFSERROR.FILE.NOT.FOUND 317Q)

(RPAQQ \IFSERROR.PROTECTION 320Q)

(RPAQQ \IFSERROR.BUSY 321Q)

(RPAQQ \IFSERROR.INVALID.DIRECTORY 322Q)

(RPAQQ \IFSERROR.ALLOCATION 323Q)

(RPAQQ \IFSERROR.USERNAME 330Q)

(RPAQQ \IFSERROR.PASSWORD 331Q)

(RPAQQ \IFSERROR.NO.LOGIN 332Q)

(RPAQQ \PASSWORD.ERRORS (330Q 331Q 332Q 337Q))

(RPAQQ \IFSERROR.CONNECTNAME 333Q)

(RPAQQ \IFSERROR.CONNECTPASSWORD 334Q)

(RPAQQ \CONNECT.PASSWORD.ERRORS (333Q 334Q))

(RPAQQ \IFSERROR.NEED.USERNAME 337Q)

(RPAQQ \IFS.ERROR.BROKEN.LEAF 1751Q)

(RPAQQ \IFSERROR.BAD.HANDLE 1763Q)


(CONSTANTS (\IFSERROR.BAD.CHARACTER 312Q)
       (\IFSERROR.MALFORMED '(311Q 312Q))
       (\IFSERROR.FILE.NOT.FOUND 317Q)
       (\IFSERROR.PROTECTION 320Q)
       (\IFSERROR.BUSY 321Q)
       (\IFSERROR.INVALID.DIRECTORY 322Q)
       (\IFSERROR.ALLOCATION 323Q)
       (\IFSERROR.USERNAME 330Q)
       (\IFSERROR.PASSWORD 331Q)
       (\IFSERROR.NO.LOGIN 332Q)
       (\PASSWORD.ERRORS '(330Q 331Q 332Q 337Q))
       (\IFSERROR.CONNECTNAME 333Q)
       (\IFSERROR.CONNECTPASSWORD 334Q)
       (\CONNECT.PASSWORD.ERRORS '(333Q 334Q))
       (\IFSERROR.NEED.USERNAME 337Q)
       (\IFS.ERROR.BROKEN.LEAF 1751Q)
       (\IFSERROR.BAD.HANDLE 1763Q))
)
(DECLARE%: EVAL@COMPILE 

(RPAQQ \PT.LEAF 260Q)

(RPAQQ \PT.ERROR 4)

(RPAQQ \LEAFOP.ANSWERBIT 2000Q)

(RPAQQ \LEAF.READBIT 100000Q)

(RPAQQ \LEAF.WRITEBIT 40000Q)

(RPAQQ \LEAF.EXTENDBIT 20000Q)

(RPAQQ \LEAF.MULTIBIT 10000Q)

(RPAQQ \LEAF.CREATEBIT 4000Q)

(RPAQQ \LEAF.DEFAULT.LOWEST 200Q)

(RPAQQ \LEAF.DEFAULT.HIGHEST 400Q)

(RPAQQ \LEAF.DEFAULT.NEXT 600Q)

(RPAQQ \LEAF.EXPLICIT.ANY 3000Q)

(RPAQQ \LEAF.EXPLICIT.OLD 1000Q)

(RPAQQ \LEAF.EXPLICIT.NEXT.OR.OLD 2000Q)

(RPAQQ \LEN.RESETLEAF 4)

(RPAQQ \LEN.LEAFPARAMS 10Q)

(RPAQQ \LEN.NOOPREQUEST 2)

(RPAQQ \LEN.OPENREQUEST 6)

(RPAQQ \LEN.FILEREQUEST 12Q)

(RPAQQ \LEN.CLOSEREQUEST 4)

(RPAQQ \LEN.READANSWER 12Q)

(RPAQQ \OPCODE.SHIFT 13Q)

(RPAQQ \LEN.CLOSEREQUEST 4)

(RPAQQ \MAXLEN.FILENAME 144Q)

(RPAQ \OFFSET.FILENAME (TIMES 2 400Q))

(RPAQQ \BYTES.PER.TRIDENT.PAGE 4000Q)

(RPAQQ \LEN.DATE 4)

(RPAQQ \LEAFMODE.DONTEXTEND 2)

(RPAQQ \LEN.FILETYPE&SIZE 4)

(RPAQQ \OFFSET.FILETYPE 1250Q)

(RPAQQ \OFFSET.BACKUPDATE 1244Q)

(RPAQQ \OFFSET.AUTHOR 1174Q)

(RPAQQ \LEN.AUTHOR 50Q)

(RPAQQ \SHORT.ERROR.PUPLEN 36Q)

(RPAQQ \LEAF.GOODSTATUS 177776Q)

(RPAQQ \LF.ALLOWERRORS 2)

(RPAQQ \LF.WANTANSWER 1)

(RPAQQ \LEAF.BROKEN.STATUS 177771Q)

(RPAQQ \LEAF.NEVER.OPENED 177773Q)


(CONSTANTS (\PT.LEAF 260Q)
       (\PT.ERROR 4)
       (\LEAFOP.ANSWERBIT 2000Q)
       (\LEAF.READBIT 100000Q)
       (\LEAF.WRITEBIT 40000Q)
       (\LEAF.EXTENDBIT 20000Q)
       (\LEAF.MULTIBIT 10000Q)
       (\LEAF.CREATEBIT 4000Q)
       (\LEAF.DEFAULT.LOWEST 200Q)
       (\LEAF.DEFAULT.HIGHEST 400Q)
       (\LEAF.DEFAULT.NEXT 600Q)
       (\LEAF.EXPLICIT.ANY 3000Q)
       (\LEAF.EXPLICIT.OLD 1000Q)
       (\LEAF.EXPLICIT.NEXT.OR.OLD 2000Q)
       (\LEN.RESETLEAF 4)
       (\LEN.LEAFPARAMS 10Q)
       (\LEN.NOOPREQUEST 2)
       (\LEN.OPENREQUEST 6)
       (\LEN.FILEREQUEST 12Q)
       (\LEN.CLOSEREQUEST 4)
       (\LEN.READANSWER 12Q)
       (\OPCODE.SHIFT 13Q)
       (\LEN.CLOSEREQUEST 4)
       (\MAXLEN.FILENAME 144Q)
       (\OFFSET.FILENAME (TIMES 2 400Q))
       (\BYTES.PER.TRIDENT.PAGE 4000Q)
       (\LEN.DATE 4)
       (\LEAFMODE.DONTEXTEND 2)
       (\LEN.FILETYPE&SIZE 4)
       (\OFFSET.FILETYPE 1250Q)
       (\OFFSET.BACKUPDATE 1244Q)
       (\OFFSET.AUTHOR 1174Q)
       (\LEN.AUTHOR 50Q)
       (\SHORT.ERROR.PUPLEN 36Q)
       (\LEAF.GOODSTATUS 177776Q)
       (\LF.ALLOWERRORS 2)
       (\LF.WANTANSWER 1)
       (\LEAF.BROKEN.STATUS 177771Q)
       (\LEAF.NEVER.OPENED 177773Q))
)
(DECLARE%: EVAL@COMPILE 

(RPAQQ \FT.TEXT 1)

(RPAQQ \FT.BINARY 2)

(RPAQQ \FT.UNKNOWN 0)


(CONSTANTS (\FT.TEXT 1)
       (\FT.BINARY 2)
       (\FT.UNKNOWN 0))
)
(DECLARE%: DOEVAL@COMPILE DONTCOPY

(LOCALVARS . T)
)
(DECLARE%: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS \LEAFDEVICE \SOCKET.LEAF LEAFDEBUGFLG PUPTRACEFLG NOFILEPROPERROR NETWORKOSTYPES 
       LEAFOPCODES SEQUINOPS DEFAULTFILETYPE \LEAF.IDLETIMEOUT \LEAF.CACHETIMEOUT \LEAF.MAXLOOKAHEAD
       \LEAF.MAXCACHE \LEAFCONNECTIONLOCK \FTPAVAILABLE UNIXFTPFLG \SEQUIN.TIMEOUTMAX LEAFABORTREGION
       \MAXLEAFTRIES \LEAF.RECOVERY.TIMEOUT NONLEAFHOSTS \FTPFDEV)
)
)

(/DECLAREDATATYPE 'PUPFILESERVER '(BYTE POINTER POINTER POINTER POINTER POINTER POINTER POINTER 
                                        POINTER POINTER POINTER POINTER)
       '((PUPFILESERVER 0 (BITS . 7))
         (PUPFILESERVER 2 POINTER)
         (PUPFILESERVER 4 POINTER)
         (PUPFILESERVER 6 POINTER)
         (PUPFILESERVER 10Q POINTER)
         (PUPFILESERVER 12Q POINTER)
         (PUPFILESERVER 14Q POINTER)
         (PUPFILESERVER 16Q POINTER)
         (PUPFILESERVER 20Q POINTER)
         (PUPFILESERVER 22Q POINTER)
         (PUPFILESERVER 24Q POINTER)
         (PUPFILESERVER 26Q POINTER))
       '30Q)
(ADDTOVAR SYSTEMRECLST

(DATATYPE PUPFILESERVER ((NIL BYTE)
                         (PFSNAME POINTER)
                         (PFSADDRESS POINTER)
                         (PFSOSTYPE POINTER)
                         (PFSLEAFFLG POINTER)
                         (PFSLEAFSEQUIN POINTER)
                         (PFSLEAFTIMER POINTER)
                         (PFSLOOKUPFILESOCKET POINTER)
                         (PFSLOOKUPFILELOCK POINTER)
                         (PFSLOOKUPFAILCNT POINTER)
                         (PFSKNOWNDIRS POINTER)
                         (NIL POINTER)))
)
(DECLARE%: DONTCOPY
  (FILEMAP (NIL (54176Q 67274Q (CLOSESEQUIN 54210Q . 55227Q) (INITSEQUIN 55231Q . 60335Q) (GETSEQUIN 
60337Q . 62050Q) (PUTSEQUIN 62052Q . 67272Q)) (67275Q 152700Q (\SEQUIN.CONTROL 67307Q . 70560Q) (
\SEQUIN.PUT 70562Q . 75605Q) (\SEQUIN.PROCESS 75607Q . 113063Q) (\SEQUIN.CLOSE 113065Q . 113752Q) (
\SEQUIN.FLUSH.CONNECTION 113754Q . 115765Q) (\SEQUIN.CLEANUP 115767Q . 117120Q) (
\SEQUIN.FLUSH.RETRANSMIT 117122Q . 120357Q) (\SEQUIN.COMPARE 120361Q . 121520Q) (\SEQUIN.HANDLE.INPUT 
121522Q . 137477Q) (\SEQUIN.OUT.OF.THE.BLUE 137501Q . 140324Q) (\SEQUIN.HANDLE.ACK 140326Q . 144560Q) 
(\SEQUIN.RETRANSMIT 144562Q . 150130Q) (\SEQUIN.RETRANSMITNEXT 150132Q . 152676Q)) (152751Q 416653Q (
\LEAF.CLOSEFILE 152763Q . 166034Q) (\LEAF.DELETEFILE 166036Q . 171621Q) (\LEAF.DEVICEP 171623Q . 
206612Q) (\LEAF.RECONNECT 206614Q . 210531Q) (\LEAF.DIRECTORYNAMEP 210533Q . 214044Q) (
\LEAF.GENERATEFILES 214046Q . 214460Q) (\LEAF.GETFILE 214462Q . 251121Q) (\PARSE.REMOTE.FILENAME 
251123Q . 260327Q) (\LEAF.STRIP.QUOTES 260331Q . 262022Q) (\LEAF.GETFILEDATES 262024Q . 264217Q) (
\LEAF.GETFILEINFO 264221Q . 267576Q) (\LEAF.GETFILEINFO.OPEN 267600Q . 276417Q) (\LEAF.GETFILENAME 
276421Q . 300636Q) (\LEAF.OPENFILE 300640Q . 314711Q) (\LEAF.READFILENAME 314713Q . 320624Q) (
\LEAF.ADD.QUOTES 320626Q . 323250Q) (\LEAF.READFILEPROP 323252Q . 326321Q) (\LEAF.READPAGES 326323Q . 
335460Q) (\LEAF.REQUESTPAGE 335462Q . 344372Q) (\LEAF.LOOKUPCACHE 344374Q . 351330Q) (CLEAR.LEAF.CACHE
 351332Q . 353302Q) (LEAF.ASSURE.FINISHED 353304Q . 360435Q) (\LEAF.FORCEOUTPUT 360437Q . 360731Q) (
\LEAF.FLUSH.CACHE 360733Q . 362137Q) (\LEAF.RENAMEFILE 362141Q . 363113Q) (\LEAF.REOPENFILE 363115Q . 
370470Q) (\LEAF.CREATIONDATE 370472Q . 371327Q) (\LEAF.SETCREATIONDATE 371331Q . 375044Q) (
\LEAF.SETFILEINFO 375046Q . 376730Q) (\LEAF.SETFILETYPE 376732Q . 403514Q) (\LEAF.SETVALIDATION 
403516Q . 406053Q) (\LEAF.TRUNCATEFILE 406055Q . 411250Q) (\LEAF.WRITEPAGES 411252Q . 416651Q)) (
416736Q 425045Q (\SENDLEAF 416750Q . 425043Q)) (425121Q 455602Q (\OPENLEAFCONNECTION 425133Q . 447241Q
) (\LEAF.BREAKCONNECTION 447243Q . 451047Q) (\CLOSELEAFCONNECTION 451051Q . 451711Q) (\LEAF.EVENTFN 
451713Q . 455600Q)) (455671Q 460454Q (BREAKCONNECTION 455703Q . 460452Q)) (460560Q 573144Q (
\LEAF.ACKED 460572Q . 461301Q) (\LEAF.FIX.BROKEN.SEQUIN 461303Q . 501243Q) (\LEAF.REPAIR.BROKEN.PUP 
501245Q . 505337Q) (\LEAF.USE.NEW.CONNECTION 505341Q . 521164Q) (\LEAF.RESENDPUPS 521166Q . 521576Q) (
\LEAF.HANDLE.INPUT 521600Q . 531110Q) (\LEAF.OPENERRORHANDLER 531112Q . 532535Q) (\LEAF.TIMEDIN 
532537Q . 533522Q) (\LEAF.TIMEDOUT 533524Q . 542037Q) (\LEAF.NOT.RESPONDING 542041Q . 543411Q) (
\LEAF.TIMEDOUT.EXCESSIVE 543413Q . 556060Q) (\LEAF.ABORT.FROMMENU 556062Q . 557011Q) (
\LEAF.STREAM.IN.QUEUE 557013Q . 563406Q) (\LEAF.IDLE 563410Q . 565450Q) (\LEAF.MAYBE.FLUSH.CACHE 
565452Q . 566543Q) (\LEAF.WHENCLOSED 566545Q . 571733Q) (\LEAF.IDLE? 571735Q . 573142Q)) (573267Q 
627102Q (\ADDLEAFSTRING 573301Q . 577147Q) (\FIXPASSWORD 577151Q . 601306Q) (\GETLEAFSTRING 601310Q . 
602040Q) (\IFSERRORSTRING 602042Q . 610227Q) (\LEAF.ERROR 610231Q . 615530Q) (\LEAF.DIRECTORYNAMEONLY 
615532Q . 616253Q) (GETHOSTINFO 616255Q . 623553Q) (GETOSTYPE 623555Q . 623774Q) (EXPANDING-PAGEFULLFN
 623776Q . 627100Q)) (627307Q 654074Q (\IFS.LOOKUPFILE 627321Q . 654072Q)) (656005Q 660134Q (\LEAFINIT
 656017Q . 660132Q)) (660212Q 673247Q (PRINTLEAF 660224Q . 673245Q)))))
STOP
