(DEFINE-FILE-INFO READTABLE "INTERLISP" PACKAGE "INTERLISP")
(FILECREATED "29-Jul-87 08:47:18" {PHYLUM}<LISPUSERS>LYRIC>UNDIGESTIFY.;2 16839  

      changes to%:  (FNS INSTALL-UNDIGESTIFY)

      previous date%: "16-May-86 10:55:33" {PHYLUM}<LISPUSERS>LYRIC>UNDIGESTIFY.;1)


(* "
Copyright (c) 1986, 1987 by Xerox Corporation.  All rights reserved.
")

(PRETTYCOMPRINT UNDIGESTIFYCOMS)

(RPAQQ UNDIGESTIFYCOMS ((INITVARS *DELETE-DIGEST-FLAG* *MOVE-TO-FIRST-DIGEST-MESSAGE-FLAG* 
                               *DONT-UPDATE-HEADERS-FLAG* SEPARATOR1 SEPARATOR2)
                        (FNS INSTALL-UNDIGESTIFY LAFITE-DISPLAY LAFITE-TRUNCATE-FILE 
                             LAFITE-UNDIGESTIFY MOVE-TO-EOL OPEN-SPACE-IN-FILE 
                             PARSE-AND-MAYBE-MERGE-HEADER SKIP-EOLS BACKUP-PTR 
                             TEDIT.FIND.NOT.CASELESS)
                        (DECLARE%: EVAL@COMPILE DONTCOPY (FILES {ERIS}<LAFITE>SOURCES>LAFITEDECLS))
                        (P (INSTALL-UNDIGESTIFY))))

(RPAQ? *DELETE-DIGEST-FLAG* NIL)

(RPAQ? *MOVE-TO-FIRST-DIGEST-MESSAGE-FLAG* NIL)

(RPAQ? *DONT-UPDATE-HEADERS-FLAG* NIL)

(RPAQ? SEPARATOR1 NIL)

(RPAQ? SEPARATOR2 NIL)
(DEFINEQ

(INSTALL-UNDIGESTIFY
  [LAMBDA NIL                                                (* ; "Edited 29-Jul-87 08:44 by Rao")
                                                             (* ; 
                       "Put 'Undigest' on the browser menu after Display, if it isn't already there.")

    (if (NOT (SASSOC "Undigest" LAFITEBROWSERMENUITEMS))
        then                                                 (* ; 
                                          "Copy the list because the menus will share its structure.")

             (SETQ LAFITEBROWSERMENUITEMS (COPY LAFITEBROWSERMENUITEMS))
             (for ITEMS on LAFITEBROWSERMENUITEMS when (EQUAL "Forward" (CAAR ITEMS))
                do (RPLACD ITEMS (CONS '("Undigest" 'LAFITE-UNDIGESTIFY 
                                               "Unpacks network digest into separate messages.")
                                       (CDR ITEMS)))
                   (RETURN T)))
          
          (* ;; "Update the width of the browser.  Use the larger of the previous width and the minimum possible width, it case they like wide browsers.")

    [AND (REGIONP LAFITEBROWSERREGION)
         (replace (REGION WIDTH) of LAFITEBROWSERREGION
            with (IMAX (fetch (REGION WIDTH) of LAFITEBROWSERREGION)
                       (fetch (REGION WIDTH)
                          of (WINDOWPROP (MENUWINDOW (create MENU
                                                            ITEMS ← LAFITEBROWSERMENUITEMS
                                                            CENTERFLG ← T
                                                            MENUFONT ← LAFITEMENUFONT))
                                    'REGION]
    (SETQ *DELETE-DIGEST-FLAG* T)
    (SETQ *MOVE-TO-FIRST-DIGEST-MESSAGE-FLAG* NIL)
    (SETQ *DONT-UPDATE-HEADERS-FLAG* NIL)
    (SETQ SEPARATOR1 '"-----------------------------------------------------------------")
    (SETQ SEPARATOR2 '"--------"])

(LAFITE-DISPLAY
  [LAMBDA (WINDOW MAILFOLDER ITEM MENU KEY)                  (* SCB%: "26-Mar-86 10:44")
    (COND
       ((EQ KEY 'LEFT)
        (\LAFITE.DISPLAY WINDOW MAILFOLDER ITEM MENU KEY))
       ((EQ KEY 'MIDDLE)
        (LAFITE-UNDIGESTIFY WINDOW MAILFOLDER ITEM MENU KEY])

(LAFITE-TRUNCATE-FILE
  [LAMBDA (FILE LENGTH)                                      (* SCB%: "30-Apr-86 14:24")
          
          (* Truncate the folder. FILE is the filename, not a stream.
          Returns T if we did the truncation.)

    (CLOSEF? FILE)
    (if (NEQ (GETFILEINFO FILE 'LENGTH)
             LENGTH)
        then (SETFILEINFO FILE 'LENGTH LENGTH)
             T])

(LAFITE-UNDIGESTIFY
  [LAMBDA (WINDOW MAILFOLDER ITEM MENU KEY)                  (* SCB%: "30-Apr-86 14:51")
    (RESETLST
     (LA.RESETSHADE ITEM MENU)
     (PROG (REPORTWINDOW MSG1 MSGN MESSAGES DIGEST-MSG-DESC MESSAGE-STREAM MESSAGE-POSITIONS 
                  DIGEST-HEADER-PARSE DIGEST-TO)
           (SETQ REPORTWINDOW (fetch (MAILFOLDER BROWSERPROMPTWINDOW) of MAILFOLDER))
           (SETQ MSG1 (fetch (MAILFOLDER FIRSTSELECTEDMESSAGE) of MAILFOLDER))
           (SETQ MSGN (fetch (MAILFOLDER LASTSELECTEDMESSAGE) of MAILFOLDER))
           (CLEARW REPORTWINDOW)
           (if (NOT (AND (NUMBERP MSG1)
                         (NUMBERP MSGN)
                         (IEQP MSG1 MSGN)))
               then (PRINTOUT REPORTWINDOW "Must select a single message.")
             else
             (PRINTOUT REPORTWINDOW "Parsing digest... ")
             (WITH.MONITOR
              (fetch FOLDERLOCK of MAILFOLDER)
              (SETQ DIGEST-MSG-DESC (NTHMESSAGE (SETQ MESSAGES (fetch (MAILFOLDER MESSAGEDESCRIPTORS)
                                                                  of MAILFOLDER))
                                           MSG1))
              (LA.COPY.MESSAGE.TEXT MAILFOLDER (SETQ MESSAGE-STREAM (OPENTEXTSTREAM))
                     DIGEST-MSG-DESC)
              (SETQ DIGEST-HEADER-PARSE (LAFITE.PARSE.HEADER MESSAGE-STREAM \LAPARSE.FULL 0 -1 NIL T)
               )
              (SETQ DIGEST-TO (CADR (ASSOC 'To DIGEST-HEADER-PARSE)))
          
          (* Parse the digest, looking for the separators between each submessage.)

              (PROG (TEXTOBJ MSGS L1 L2 P1 P2 P3)
                    (SETQ TEXTOBJ (TEXTOBJ MESSAGE-STREAM))
                    (SETQ MSGS NIL)
                    (SETQ L1 (NCHARS SEPARATOR1))
                    (SETQ L2 (NCHARS SEPARATOR2))
                    (SETQ P1 (TEDIT.FIND.NOT.CASELESS TEXTOBJ SEPARATOR1 1))
                    (if (NULL P1)
                        then (PRINTOUT REPORTWINDOW "Can't find first separator.")
                             (GO ERROR))
                    [SETQ P1 (SKIP-EOLS MESSAGE-STREAM (MOVE-TO-EOL MESSAGE-STREAM (IPLUS P1 L1]
                    (if (EQ 'ERROR (PARSE-AND-MAYBE-MERGE-HEADER MESSAGE-STREAM P1 (IPLUS P1 1000)
                                          DIGEST-TO))
                        then (PRINTOUT REPORTWINDOW "Can't parse header of digest message #1")
                             (GO ERROR))
                    (SETQ P2 P1)
          
          (* P1 points to the beginning of the message.
          P2 points to the separator that might end the message.
          P3 points to the beginning of the next message's header.)

                    (until (NULL (SETQ P2 (TEDIT.FIND.NOT.CASELESS TEXTOBJ SEPARATOR2 P2)))
                       do [SETQ P3 (SKIP-EOLS MESSAGE-STREAM (MOVE-TO-EOL MESSAGE-STREAM
                                                                    (IPLUS P2 L2]
                          (if (EQ 'ERROR (PARSE-AND-MAYBE-MERGE-HEADER MESSAGE-STREAM P3
                                                (IPLUS P3 1000)
                                                DIGEST-TO))
                              then (SETQ P2 P3)              (* Keep looking for end of message.)
                            else 
          
          (* Message ends at char just before P2 because of TEDIT.FIND.NOT.CASELESS)

                                 (push MSGS (LIST P1 (SUB1 P2)))
                                 (SETQ P1 P3)
                                 (SETQ P2 P3)))
          
          (* We're allowed to throw away up to 50 characters at the end of the message.)

                    [if (IGEQ (IDIFFERENCE (GETEOFPTR MESSAGE-STREAM)
                                     P1)
                              50)
                        then (push MSGS (LIST P1 (GETEOFPTR MESSAGE-STREAM]
                    (SETQ MESSAGE-POSITIONS (DREVERSE MSGS))
                    (RETURN)
                ERROR
                    (SETQ MESSAGE-POSITIONS 'ERROR)
                    (RETURN))
              (if (EQ 'ERROR MESSAGE-POSITIONS)
                  then (PRINTOUT REPORTWINDOW "  Aborted.")
                else (PROG (OUTSTREAM BEGIN MSG-DESC MSG-START MSG-END NEW-MESSAGE-DESCRIPTORS)
                           (SETQ OUTSTREAM (\LAFITE.OPEN.FOLDER MAILFOLDER 'OUTPUT))
          
          (* Protect against the user typing an interrupt char while we're writing to the 
          mailfolder.)

                           [RESETSAVE NIL `(AND RESETSTATE (LAFITE-TRUNCATE-FILE
                                                            ',(fetch (MAILFOLDER 
                                                                            VERSIONLESSFOLDERNAME)
                                                                 of MAILFOLDER)
                                                            ',(fetch (MAILFOLDER FOLDEREOFPTR)
                                                                 of MAILFOLDER]
                           (SETFILEPTR OUTSTREAM -1)
                           [COND
                              ((NOT (IEQP (SETQ BEGIN (GETFILEPTR OUTSTREAM))
                                          (fetch FOLDEREOFPTR of MAILFOLDER)))
                               (RETURN (HELP "Folder inconsistent with browser"]
                           (SETQ NEW-MESSAGE-DESCRIPTORS NIL)
                           (for MSG-POS in MESSAGE-POSITIONS
                              do (SETQ MSG-START (CAR MSG-POS))
                                 (SETQ MSG-END (CADR MSG-POS))
                                 [SETQ MSG-DESC
                                  (create LAFITEMSG
                                         BEGIN ← BEGIN
                                         SEEN? ← NIL
                                         MARKCHAR ← UNSEENMARK
                                         STAMPLENGTH ← LAFITESTAMPLENGTH
                                         MESSAGELENGTH ← (SETQ LEN (IPLUS LAFITESTAMPLENGTH
                                                                          (IDIFFERENCE MSG-END 
                                                                                 MSG-START]
                                 (push NEW-MESSAGE-DESCRIPTORS MSG-DESC)
                                 (SETQ BEGIN (IPLUS BEGIN LEN))
                                 (LA.PRINTSTAMP OUTSTREAM)
                                 (LA.PRINTCOUNT LEN OUTSTREAM)
                                 (LA.PRINTCOUNT LAFITESTAMPLENGTH OUTSTREAM)
                                 (BOUT OUTSTREAM UNDELETEDFLAG)
                                 (BOUT OUTSTREAM SEENFLAG)
                                 (BOUT OUTSTREAM SEENMARK)
                                 (BOUT OUTSTREAM (CHARCODE CR))
                                 (COPYBYTES MESSAGE-STREAM OUTSTREAM MSG-START MSG-END))
                           (LAB.APPENDMESSAGES MAILFOLDER (SETQ NEW-MESSAGE-DESCRIPTORS (DREVERSE
                                                                                         
                                                                              NEW-MESSAGE-DESCRIPTORS
                                                                                         )))
                           (SEENMESSAGE DIGEST-MSG-DESC MAILFOLDER)
                           (if *DELETE-DIGEST-FLAG*
                               then (DELETEMESSAGE DIGEST-MSG-DESC MAILFOLDER))
                           [if *MOVE-TO-FIRST-DIGEST-MESSAGE-FLAG*
                               then (UNSELECTALLMESSAGES MAILFOLDER)
                                    (SELECTMESSAGE (CAR NEW-MESSAGE-DESCRIPTORS)
                                           MAILFOLDER)
                                    (LAB.EXPOSEMESSAGE MAILFOLDER (CAR NEW-MESSAGE-DESCRIPTORS))
                             else 
          
          (* Treat digest message as if it had been displayed, and move to next undeleted 
          message.)

                                  (for N from (ADD1 MSG1) to (fetch (MAILFOLDER %#OFMESSAGES)
                                                                of MAILFOLDER)
                                     do (if [NOT (fetch (LAFITEMSG DELETED?)
                                                    of (SETQ MSG-DESC (NTHMESSAGE MESSAGES N]
                                            then (LA.SHOW.SELECTION MAILFOLDER DIGEST-MSG-DESC
                                                        'ERASE)
                                                 (LA.SHOW.SELECTION MAILFOLDER MSG-DESC 'REPLACE)
                                                 (replace (LAFITEMSG SELECTED?) of DIGEST-MSG-DESC
                                                    with NIL)
                                                 (replace (LAFITEMSG SELECTED?) of MSG-DESC
                                                    with T)
                                                 (replace FIRSTSELECTEDMESSAGE of MAILFOLDER
                                                    with N)
                                                 (replace LASTSELECTEDMESSAGE of MAILFOLDER
                                                    with N)
                                                 (RETURN]
                           (PRINTOUT REPORTWINDOW " done. "])

(MOVE-TO-EOL
  [LAMBDA (TEXTSTREAM POSITION)                              (* SCB%: "27-Mar-86 10:34")
          
          (* POSITION points into a line. Return the position immediately following the 
          CR at the end of this line, i.e., the first char on the next line.)

    (AND POSITION (SETFILEPTR TEXTSTREAM POSITION))
    (until (IEQP (CHARCODE CR)
                 (\BIN TEXTSTREAM)) do)
    (GETFILEPTR TEXTSTREAM])

(OPEN-SPACE-IN-FILE
  [LAMBDA (FILE POSITION NCHARS)                             (* SCB%: "25-Mar-86 12:52")
          
          (* Open a space in file starting at POSITION for length NCHARS by sliding the 
          rest of the file down.)

    (LET [(TEMP (OPENFILE '{NODIRCORE} 'BOTH]
         (COPYBYTES FILE TEMP POSITION (GETEOFPTR FILE))
         (SETFILEPTR FILE (IPLUS POSITION NCHARS))
         (SETFILEPTR TEMP 0)
         (COPYBYTES TEMP FILE)
         (CLOSEF? TEMP])

(PARSE-AND-MAYBE-MERGE-HEADER
  [LAMBDA (MESSAGE-STREAM P1 P2 DIGEST-TO)                   (* SCB%: "14-Apr-86 12:31")
    (PROG (MSG-HEADER-PARSE END-OF-HEADER STRING CR)
          (SETQ MSG-HEADER-PARSE (LAFITE.PARSE.HEADER MESSAGE-STREAM \LAPARSE.FULL P1 P2 NIL T))
          (if (NULL (CDR MSG-HEADER-PARSE))
              then                                           (* Nothing in the header, probably not 
                                                             a legal message.)
                   (RETURN 'ERROR))
          (if *DONT-UPDATE-HEADERS-FLAG*
              then (RETURN P2))
          (SETQ END-OF-HEADER (CADR (ASSOC 'EOF MSG-HEADER-PARSE)))
          (if (NULL (ASSOC 'To MSG-HEADER-PARSE))
              then (TEDIT.INSERT MESSAGE-STREAM (SETQ STRING (CONCAT (SETQ CR (CHARACTER (CHARCODE
                                                                                          CR)))
                                                                    "To: " DIGEST-TO CR))
                          END-OF-HEADER)
                   (add END-OF-HEADER (NCHARS STRING))
                   (add P2 (NCHARS STRING)))
          (RETURN P2])

(SKIP-EOLS
  [LAMBDA (TEXTSTREAM POSITION)                              (* SCB%: "27-Mar-86 10:35")
    (AND POSITION (SETFILEPTR TEXTSTREAM POSITION))
    (until (NOT (IEQP (CHARCODE CR)
                      (\BIN TEXTSTREAM))) do)
    (SETFILEPTR TEXTSTREAM (SUB1 (GETFILEPTR TEXTSTREAM])

(BACKUP-PTR
  [LAMBDA (STREAM)                                           (* SCB%: "27-Mar-86 10:20")
    (SETFILEPTR STREAM (SUB1 (GETFILEPTR STREAM])

(TEDIT.FIND.NOT.CASELESS
  [LAMBDA (TEXTOBJ TARGETSTRING START# END# WILDCARDS?)      (* SCB%: " 9-Apr-86 13:53")
          
          (* This function exists because you might be using Shrager's caseless search in 
          TEdit.)

    (LET ((TEDIT%:*CASE-FOLD-SEARCH-P* NIL))
         (TEDIT.FIND TEXTOBJ TARGETSTRING START# END# WILDCARDS?])
)
(DECLARE%: EVAL@COMPILE DONTCOPY 
(FILESLOAD {ERIS}<LAFITE>SOURCES>LAFITEDECLS)
)
(INSTALL-UNDIGESTIFY)
(PUTPROPS UNDIGESTIFY COPYRIGHT ("Xerox Corporation" 1986 1987))
(DECLARE%: DONTCOPY
  (FILEMAP (NIL (1217 16647 (INSTALL-UNDIGESTIFY 1227 . 3240) (LAFITE-DISPLAY 3242 . 3541) (
LAFITE-TRUNCATE-FILE 3543 . 3954) (LAFITE-UNDIGESTIFY 3956 . 13612) (MOVE-TO-EOL 13614 . 14074) (
OPEN-SPACE-IN-FILE 14076 . 14578) (PARSE-AND-MAYBE-MERGE-HEADER 14580 . 15800) (SKIP-EOLS 15802 . 
16113) (BACKUP-PTR 16115 . 16277) (TEDIT.FIND.NOT.CASELESS 16279 . 16645)))))
STOP