; -*- Mode:LISP; Package:ZWEI; Base:8; Readtable:ZL -*- ;;; Operating system dependent mail file handling, extension of MFILES ; ** (c) Copyright 1982 Massachusetts Institute of Technology ** ; An invalid Enhancements copyright notice on AI:ZMAIL; MFHOST 15 removed on 3/31/82 by RG ; This file had been installed as the official MIT source in direct contravention ; to instructions to Symbolics personnel acting on MIT's behalf. (DEFVAR *ZMAIL-HOMEDIR-REAL-NEW-MAIL-FILENAME* NIL "If non-NIL, pretend this is where we always should get new mail for FS:USER-ID.") (DEFVAR *REAL-MAIL-FILE-HOST-ALIST* NIL "An alist of hosts and a real file name to override what file to get new mail for ourselves.") (DEFUN MAYBE-OVERRIDDEN-MAIL-PATHNAME (PATHNAME &OPTIONAL (USER USER-ID) &AUX VALUE) "Return the pathname of the mail file if it is overridden by PATHNAME, else NIL." (UNLESS (NOT (STRING-EQUAL FS::USER-ID USER)) ;;if its for someone else, its not overridden (OR (AND (EQ (FS::USER-HOMEDIR) PATHNAME) ;;override it with this variable *ZMAIL-HOMEDIR-REAL-NEW-MAIL-FILENAME*) (LET ((HOST (SEND PATHNAME :HOST))) (DOLIST (ELEM *REAL-MAIL-FILE-HOST-ALIST*) (COND ((EQ HOST (SI:PARSE-HOST (CAR ELEM) T)) (SETQ VALUE (CDR ELEM))))) VALUE)))) ;;; The :DO-MSGS method returns the file to find the messages in (DEFMETHOD (SI:HOST :DO-GMSGS) (STREAM) (MULTIPLE-VALUE-BIND (FILE-NAME UNAME-STRING) (SEND SELF :GMSGS-PATHNAME) (WITH-OPEN-STREAM (CSTREAM (CHAOS:OPEN-STREAM SELF (GMSGS-CONTACT-NAME FILE-NAME UNAME-STRING) :DIRECTION :INPUT :ERROR ())) (IF (ERRORP CSTREAM) (FORMAT *QUERY-IO* "~&GMSGS Error: ~A" CSTREAM) (STREAM-COPY-UNTIL-EOF CSTREAM STREAM))) FILE-NAME)) (DEFUN GMSGS-CONTACT-NAME (INBOX USER-STRING) (STRING-APPEND "GMSGS " USER-STRING " " (IF (EQ (SEND INBOX :SYSTEM-TYPE) :ITS) "//G" "") *GMSGS-OTHER-SWITCHES* " ")) ; 20X lossage ;;; :GMSGS-PATHNAME should return two values: the expected GMSGS inbox for ZMAIL ;;; and a string which determines the user (or his GMSGS inbox in the case of ITS). (DEFMETHOD (SI:HOST :GMSGS-PATHNAME) () (VALUES (SEND (FS::USER-HOMEDIR SELF) :NEW-PATHNAME :NAME "GMSGS" :CANONICAL-TYPE :TEXT) (OR (FS::UNAME-ON-HOST SELF) USER-ID))) ;;; ITS mail files (DEFFLAVOR ITS-MAIL-FILE-MIXIN () () :ABSTRACT-FLAVOR (:REQUIRED-FLAVORS ZMAIL-DISK-BUFFER)) (DEFMETHOD (ITS-MAIL-FILE-MIXIN :HEADER-COMPATIBLE-MAIL-FILE-FORMATS) () '("Mail" "Rmail" "Babyl" "Tenex mail")) (DEFFLAVOR ITS-INBOX-BUFFER () (ITS-MAIL-FILE-MIXIN INBOX-BUFFER)) (DEFMETHOD (ITS-INBOX-BUFFER :FORMAT-NAME) () "Mail") ;;should have a similar kludge for determining the inbox filename (DEFMETHOD (FS::ITS-PATHNAME-MIXIN :MAIL-FILE-FORMAT-COMPUTER) (STREAM &AUX FLAVOR APPEND-P) (IF (NULL STREAM) (SETQ FLAVOR 'RMAIL-FILE-BUFFER) (LET ((FIRST-LINE (SEND STREAM :LINE-IN))) (SEND STREAM :SET-POINTER 0) (IF (STRING-EQUAL FIRST-LINE "Babyl Options:") ;; Looks like a babyl file (SETQ FLAVOR 'BABYL-MAIL-FILE-BUFFER) ;; Default is rmail file (SETQ FLAVOR 'RMAIL-FILE-BUFFER) (AND (STRING-EQUAL FIRST-LINE "*APPEND*") (SETQ APPEND-P T))))) (VALUES FLAVOR APPEND-P)) (DEFVAR *ZMAIL-FILE-FN2S* '("BABYL" "RMAIL")) (DEFMETHOD (FS::ITS-PATHNAME-MIXIN :POSSIBLE-MAIL-FILE-NAMES) () (LOOP FOR FN2 IN *ZMAIL-FILE-FN2S* COLLECT (SEND SELF :NEW-PATHNAME :NAME USER-ID :TYPE FN2 :VERSION :NEWEST))) (DEFMETHOD (FS::ITS-PATHNAME-MIXIN :POSSIBLE-MAIL-FILE-BUFFER-FLAVORS) () '(RMAIL-FILE-BUFFER BABYL-MAIL-FILE-BUFFER)) (DEFMETHOD (FS::ITS-PATHNAME-MIXIN :NEW-MAIL-PATHNAME) () (OR (MAYBE-OVERRIDDEN-MAIL-PATHNAME SELF) (SEND SELF :NEW-PATHNAME :NAME (OR FS::NAME USER-ID) :TYPE "MAIL"))) (DEFMETHOD (FS::ITS-PATHNAME-MIXIN :ZMAIL-TEMP-FILE-NAME) () (STRING-APPEND "_Z" (SEND SELF :TYPE))) (DEFMETHOD (FS::ITS-PATHNAME-MIXIN :INBOX-BUFFER-FLAVOR) () 'ITS-INBOX-BUFFER) (DEFMETHOD (SI:HOST-ITS-MIXIN :GMSGS-PATHNAME) () (LET* ((HOMEDIR (FS::USER-HOMEDIR SELF)) (INBOX (SEND (SEND HOMEDIR :NEW-PATHNAME :TYPE "GMSGS") :NEW-SUGGESTED-NAME (FS::UNAME-ON-HOST SELF)))) (VALUES INBOX (FORMAT () "~A;~A" (SEND INBOX :DIRECTORY) (SEND INBOX :NAME))))) (DEFMETHOD (ITS-MAIL-FILE-MIXIN :MAIL-FILE-REPARSABLE-P) () T) ;;; Messages on ITS end with a line with a  in it ;;; The MSG-END-BP will be before the . ;;; The MSG-REAL-END-BP is the start of the following line. (DEFMETHOD (ITS-MAIL-FILE-MIXIN :LINE-END-OF-MSG-P) (LINE LENGTH &REST IGNORE &AUX END-IDX) (AND (> LENGTH 0) (SETQ END-IDX (STRING-SEARCH-CHAR #\ LINE)) (NOT (DO I (1+ END-IDX) (1+ I) ( I LENGTH) (OR (MEMQ (CHAR LINE I) '(#/SP #/TAB #/FF)) (RETURN T)))) END-IDX)) (DEFMETHOD (ITS-MAIL-FILE-MIXIN :CANONICAL-LAST-LINE) (&AUX LINE) (SETQ LINE (CREATE-LINE 'ART-STRING 1 NIL)) (SETF (CHAR LINE 0) #\) LINE) (DEFMETHOD (ITS-MAIL-FILE-MIXIN :NEW-HEADER-AND-TRAILER) () (VALUES "" #\NewLine)) ;; Our goal state is Return  Return text-of-next-message (DEFMETHOD (ITS-MAIL-FILE-MIXIN :UPDATE-MSG-END) (MSG &OPTIONAL FOR-APPEND-P) (DECLARE (IGNORE FOR-APPEND-P)) (LET ((END-LINE (BP-LINE (MSG-END-BP MSG))) (REAL-END-BP (MSG-REAL-END-BP MSG))) ;; Other mail file formats leave the end-bp and the real-end-bp on the same line. ;; Fix that. (WHEN (EQ END-LINE (BP-LINE REAL-END-BP)) (IF (MEMBER (LINE-PREVIOUS END-LINE) '(" " "")) (SETQ END-LINE (LINE-PREVIOUS END-LINE)) (INSERT-MOVING REAL-END-BP #\RETURN) (SETQ END-LINE (LINE-PREVIOUS (BP-LINE REAL-END-BP))))) (MOVE-BP (MSG-END-BP MSG) END-LINE 0) (SETF (LINE-LENGTH END-LINE) 0) (VECTOR-PUSH-EXTEND #\ END-LINE))) (DEFMETHOD (ITS-MAIL-FILE-MIXIN :PARSE-MSG-TEXT) (MSG -STATUS-) (PARSE-ITS-MSG-HEADERS (MSG-INTERVAL MSG) NIL NIL (GET -STATUS- :REFORMATTED))) (DEFMETHOD (ITS-INBOX-BUFFER :BEFORE :PARSE-MSG) (MSG -STATUS-) MSG (PUTPROP -STATUS- T 'UNSEEN)) ;;; RMAIL mail files (ADD-ZMAIL-BUFFER-FLAVOR 'RMAIL-FILE-BUFFER "Rmail") (DEFFLAVOR RMAIL-FILE-BUFFER () (ITS-MAIL-FILE-MIXIN MAIL-FILE-BUFFER)) (DEFMETHOD (RMAIL-FILE-BUFFER :FORMAT-NAME) () "Rmail") (DEFMETHOD (RMAIL-FILE-BUFFER :AFTER :INIT) (PLIST) ;; If APPEND-P, flush the *APPEND* line from the stream, it is not part of a message. (AND (GET PLIST :APPEND-P) STREAM (INSERT-LINE-WITH-LEADER (SEND STREAM :LINE-IN LINE-LEADER-SIZE) (BP-LINE FIRST-BP)))) (DEFMETHOD (RMAIL-FILE-BUFFER :SETTABLE-OPTIONS) () '(:APPEND)) (DEFMETHOD (RMAIL-FILE-BUFFER :FIRST-MSG-BP) () (LET* ((LINE (BP-LINE FIRST-BP))) (IF (STRING-EQUAL LINE "*APPEND*") (CREATE-BP (LINE-NEXT LINE) 0) FIRST-BP))) (DEFMETHOD (RMAIL-FILE-BUFFER :UPDATE-OPTIONS-IN-FILE) () (LET* ((LINE (BP-LINE FIRST-BP)) (APPEND-P (GET (LOCF OPTIONS) :APPEND))) (COND ((EQ (STRING-EQUAL LINE "*APPEND*") APPEND-P)) (APPEND-P (INSERT FIRST-BP "*APPEND* ")) (T (DELETE-INTERVAL FIRST-BP (BEG-LINE FIRST-BP 1 T) T))))) ;;; BABYL mail files (ADD-ZMAIL-BUFFER-FLAVOR 'BABYL-MAIL-FILE-BUFFER "Babyl") ;;; Limits of Babyl file formats supported here (DEFPARAMETER *LOWEST-BABYL-VERSION* 4) (DEFPARAMETER *HIGHEST-BABYL-VERSION* 5) (DEFFLAVOR BABYL-MAIL-FILE-BUFFER () (ITS-MAIL-FILE-MIXIN MAIL-FILE-BUFFER)) (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :FORMAT-NAME) () "Babyl") (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :SETTABLE-OPTIONS) () '(:APPEND :REVERSE-NEW-MAIL :VERSION :MAIL :OWNER :SORT :DELETE-EXPIRED :|NO REFORMATION| :SUMMARY-WINDOW-FORMAT :GMSGS-HOST)) (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :POSSIBLE-OPTIONS) () '(:APPEND :BABYL-P :|NO REFORMATION| :REVERSE-NEW-MAIL :VERSION :MAIL :OWNER :SORT :DELETE-EXPIRED :KEYWORDS :KEYWORDS-STRING :SUMMARY-WINDOW-FORMAT :GMSGS-HOST)) (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :STICKY-OPTIONS) () (SOME-PLIST OPTIONS '(:APPEND :BABYL-P))) ;;; Read the options section of the mail file (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :AFTER :INIT) (PLIST) (IF STREAM (SETQ OPTIONS (PARSE-BABYL-OPTIONS STREAM SELF)) (OR (GET (LOCF OPTIONS) :VERSION) (PUTPROP (LOCF OPTIONS) *HIGHEST-BABYL-VERSION* :VERSION)) (AND (GET PLIST :NEW-PRIMARY-P) (NOT (GET (LOCF OPTIONS) :MAIL)) (PUTPROP (LOCF OPTIONS) (NCONS (SEND PATHNAME :NEW-MAIL-PATHNAME)) :MAIL)) (INSERT LAST-BP #\))) (DEFUN PARSE-BABYL-OPTIONS (STREAM INTERVAL) (FS::SET-DEFAULT-PATHNAME (SEND STREAM :PATHNAME) *ZMAIL-PATHNAME-DEFAULTS*) (DO ((END-LINE (BP-LINE (INTERVAL-LAST-BP INTERVAL))) (LINE) (LIST NIL)) (NIL) (SETQ LINE (SEND STREAM :LINE-IN LINE-LEADER-SIZE)) (INSERT-LINE-WITH-LEADER LINE END-LINE) (AND (STRING-SEARCH-CHAR #\ LINE) (RETURN LIST)) (SETQ LIST (APPEND LIST (OPTION-FROM-STRING LINE))))) (DEFPARAMETER *OPTION-SPECIAL-CHARS* '(#/( #/" #// #/0 #/1 #/2 #/3 #/4 #/5 #/6 #/7 #/8 #/9) "A list of (real) characters to be handled specially in Babyl format") ;;; Parse a single line of a babyl option or an unparsed message header (DEFUN OPTION-FROM-STRING (STRING &AUX I TYPE PARSE-FUNCTION PROP) (SETQ I (STRING-SEARCH-CHAR #\: STRING) TYPE (INTERN (STRING-UPCASE (NSUBSTRING STRING 0 I)) "")) (AND I (SETQ I (OR (STRING-SEARCH-NOT-SET '(#\SP #\TAB) STRING (SETQ I (1+ I))) (STRING-LENGTH STRING)))) (IF (SETQ PARSE-FUNCTION (GET TYPE 'BABYL-OPTION-PARSER)) (FUNCALL PARSE-FUNCTION TYPE STRING I) (COND ((NULL I) (SETQ PROP T)) ((MEMQ (CHAR STRING I) *OPTION-SPECIAL-CHARS*) (LET ((*PACKAGE* (FIND-PACKAGE 'KEYWORD)) (*READ-BASE* 10.)) (SETQ PROP (READ-FROM-STRING STRING NIL I)))) (T (SETQ PROP (SUBSTRING STRING I)))) (LIST TYPE PROP))) (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :UPDATE-OPTIONS-IN-FILE) (&AUX PLIST) (FS::SET-DEFAULT-PATHNAME PATHNAME *ZMAIL-PATHNAME-DEFAULTS*) (SETQ PLIST (LOCF OPTIONS)) ;; Move this to the first (COND ((OR (NEQ (CAAR PLIST) :BABYL-P) (NEQ (CADAR PLIST) T)) (REMPROP PLIST :BABYL-P) (PUTPROP PLIST T :BABYL-P))) (DO ((LINE (BP-LINE FIRST-BP) (LINE-NEXT LINE)) (DONE NIL) (PROPS)) ((STRING-SEARCH #\ LINE) (LOOP FOR (IND PROP) ON (CDR PLIST) BY 'CDDR WITH BP = (CREATE-BP LINE 0) WHEN (AND PROP (NOT (MEMQ IND DONE)) (GETL IND '(BABYL-OPTION-PARSER BABYL-OPTION-PRINTER BABYL-OPTION-P))) DO (SETQ LINE (STRING-FROM-OPTION IND PLIST) BP (INSERT (INSERT BP LINE) #\NewLine)) (LOOP FOR IND IN (OPTION-FROM-STRING LINE) BY 'CDDR DO (PUSH IND DONE)))) (SETQ PROPS (OPTION-FROM-STRING LINE)) (AND (LOOP FOR (IND PROP) ON PROPS BY 'CDDR UNLESS (EQUAL PROP (GET PLIST IND)) RETURN T) ;Not still the same (IF (NOT (LOOP FOR (IND PROP) ON PROPS BY 'CDDR WHEN (GET PLIST IND) RETURN T)) ;All properties NIL (LET ((BP (CREATE-BP LINE 0))) (DELETE-INTERVAL BP (BEG-LINE BP 1 T) T)) (MUNG-NODE (LINE-NODE LINE)) (SETF (LINE-LENGTH LINE) 0) (STRING-FROM-OPTION (CAR PROPS) PLIST LINE))) (LOOP FOR IND IN PROPS BY 'CDDR DO (PUSH IND DONE)))) ;;; Convert a message header into a string (DEFUN STRING-FROM-OPTION (PROP PLIST &OPTIONAL STRING &AUX VAL TEM) (OR STRING (SETQ STRING (MAKE-EMPTY-STRING 40))) (SETQ VAL (GET PLIST PROP)) (WITH-OUTPUT-TO-STRING (STREAM STRING) (COND ((SETQ TEM (GET PROP 'BABYL-OPTION-PRINTER)) (FUNCALL TEM STREAM PROP VAL PLIST)) (T (FORMAT STREAM "~:" PROP) (COND ((NEQ VAL T) (FUNCALL STREAM :TYO #\:) (LET ((*PRINT-BASE* 10.) (*NOPOINT T) (*PRINT-RADIX* NIL)) (FUNCALL (IF (AND (STRINGP VAL) (NOT (MEMQ (CHAR VAL 0) *OPTION-SPECIAL-CHARS*)) (NOT (STRING-SEARCH-SET '(#\SP #\TAB) VAL))) #'PRINC #'PRIN1) VAL STREAM))))))) STRING) ;;; The options themselves (DEFINE-NOT-SETTABLE-MAIL-FILE-OPTION :BABYL-P) (DEFUN (:|BABYL OPTIONS| BABYL-OPTION-PARSER) (&REST IGNORE) '(:BABYL-P T)) (DEFUN (:BABYL-P BABYL-OPTION-PRINTER) (STREAM &REST IGNORE) (FORMAT STREAM "Babyl Options:")) (DEFINE-SETTABLE-MAIL-FILE-OPTION :VERSION 5 :NUMBER) (DEFUN (:VERSION BABYL-OPTION-PARSER) (IGNORE STRING START &AUX VERSION) (SETQ VERSION (PARSE-NUMBER STRING START)) (AND (OR (NULL VERSION) (< VERSION *LOWEST-BABYL-VERSION*) (> VERSION *HIGHEST-BABYL-VERSION*)) (CERROR T NIL NIL "Babyl version is ~D, not supported by this version of ZMail" VERSION)) `(:VERSION ,VERSION)) (DEFINE-SETTABLE-MAIL-FILE-OPTION :|NO REFORMATION| NIL :BOOLEAN) (DEFPROP :|NO REFORMATION| T BABYL-OPTION-P) (DEFINE-SETTABLE-MAIL-FILE-OPTION :GMSGS-HOST NIL :STRING-OR-NIL) (DEFPROP :GMSGS-HOST T BABYL-OPTION-P) (DEFINE-SETTABLE-MAIL-FILE-OPTION :OWNER NIL :STRING-OR-NIL) (DEFPROP :OWNER T BABYL-OPTION-P) (DEFPROP :STRING-OR-NIL (PRINT-STRING-OR-NIL READ-STRING-OR-NIL) TV::CHOOSE-VARIABLE-VALUES-KEYWORD) (DEFUN PRINT-STRING-OR-NIL (STRING STREAM) (AND STRING (SEND STREAM :STRING-OUT STRING))) (DEFUN READ-STRING-OR-NIL (STREAM &AUX STRING) (SETQ STRING (READLINE STREAM)) (AND (PLUSP (STRING-LENGTH STRING)) STRING)) (DEFINE-SETTABLE-MAIL-FILE-OPTION :MAIL NIL :PATHNAME-LIST) (DEFPROP :MAIL PATHNAME-LIST-OPTION-PARSER BABYL-OPTION-PARSER) (DEFUN PATHNAME-LIST-OPTION-PARSER (TYPE STRING START) (DO ((I START (1+ J)) (J) (PATHNAME-LIST NIL)) (NIL) (OR (SETQ I (STRING-SEARCH-NOT-SET *WHITESPACE-CHARS* STRING I)) (RETURN NIL)) (SETQ J (STRING-SEARCH-CHAR #\, STRING I)) (PUSH (FS::MERGE-PATHNAME-DEFAULTS (NSUBSTRING STRING I J) *ZMAIL-PATHNAME-DEFAULTS*) PATHNAME-LIST) (OR J (RETURN (LIST TYPE (NREVERSE PATHNAME-LIST)))))) (DEFPROP :MAIL PATHNAME-LIST-OPTION-PRINTER BABYL-OPTION-PRINTER) (DEFUN PATHNAME-LIST-OPTION-PRINTER (STREAM PROP PATHNAME-LIST IGNORE) (FORMAT STREAM "~:: ~{~A~^, ~}" PROP PATHNAME-LIST)) (DEFINE-SETTABLE-MAIL-FILE-OPTION :REVERSE-NEW-MAIL NIL :BOOLEAN) (DEFUN (:APPEND BABYL-OPTION-PARSER) (IGNORE STRING START &AUX APPEND REVERSE) (IF (NULL START) ;Append (SETQ APPEND T) (LET ((N (PARSE-NUMBER STRING START NIL 8))) (SETQ APPEND (BIT-TEST N 1) REVERSE (BIT-TEST N 2)))) `(:APPEND ,APPEND :REVERSE-NEW-MAIL ,REVERSE)) (DEFPROP :APPEND PRINT-APPEND-AND-REVERSE-NEW-MAIL BABYL-OPTION-PRINTER) (DEFPROP :REVERSE-NEW-MAIL PRINT-APPEND-AND-REVERSE-NEW-MAIL BABYL-OPTION-PRINTER) (DEFUN PRINT-APPEND-AND-REVERSE-NEW-MAIL (STREAM IGNORE IGNORE PLIST &AUX (BITS 0)) (AND (GET PLIST :APPEND) (SETQ BITS (LOGIOR BITS 1))) (AND (GET PLIST :REVERSE-NEW-MAIL) (SETQ BITS (LOGIOR BITS 2))) (FORMAT STREAM "Append:~O" BITS)) (DEFINE-SETTABLE-MAIL-FILE-OPTION :SUMMARY-WINDOW-FORMAT *DEFAULT-SUMMARY-TEMPLATE* :SEXP) (DEFPROP :SUMMARY-WINDOW-FORMAT SEXP-OPTION-PARSER BABYL-OPTION-PARSER) (DEFUN SEXP-OPTION-PARSER (TYPE STRING START) `(,TYPE ,(READ-FROM-STRING STRING NIL START))) (DEFPROP :SUMMARY-WINDOW-FORMAT SEXP-OPTION-PRINTER BABYL-OPTION-PRINTER) (DEFUN SEXP-OPTION-PRINTER (STREAM PROP SEXP IGNORE) (FORMAT STREAM "~:: ~S" PROP SEXP)) (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :INBOX-BUFFER) (&OPTIONAL NEW-PATHNAME DELETE-P) (MAKE-INBOX-BUFFER (FUNCALL PATHNAME :INBOX-BUFFER-FLAVOR) (IF NEW-PATHNAME (LIST (LIST NEW-PATHNAME NIL DELETE-P)) (LOOP FOR NEW-PATHNAME IN (IF *RUN-GMSGS-P* (CONS (SEND (ZMAIL-BUFFER-GMSGS-HOST SELF) :GMSGS-PATHNAME) (GET (LOCF OPTIONS) :MAIL)) (GET (LOCF OPTIONS) :MAIL)) COLLECT (LIST NEW-PATHNAME (FUNCALL NEW-PATHNAME :NEW-TYPE (SEND NEW-PATHNAME :ZMAIL-TEMP-FILE-NAME)) T))) SELF)) (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :BEFORE :PARSE-MSG) (MSG -STATUS-) (LET* ((START-BP (MSG-START-BP MSG)) (END-BP (MSG-END-BP MSG)) (REAL-START-LINE (BP-LINE (MSG-REAL-START-BP MSG))) (END-LINE (BP-LINE END-BP)) (START-LINE REAL-START-LINE)) (DO () ((NOT (LINE-BLANK-P START-LINE))) (SETQ START-LINE (LINE-NEXT START-LINE))) (FUNCALL (IF (< (GET (LOCF OPTIONS) :VERSION) 5) #'PARSE-MSG-OLD-BABYL-STATUS-LINE #'PARSE-MSG-NEW-BABYL-STATUS-LINE) START-LINE -STATUS-) (DO ((LINE START-LINE (LINE-NEXT LINE))) ((EQ LINE END-LINE)) (COND ((STRING-EQUAL LINE "*** EOOH ***") (SETQ START-LINE LINE) (RETURN NIL)))) (SETQ END-LINE (LINE-NEXT START-LINE)) ;;Make lines in the header area point to MSG-REAL-INTERVAL rather than ;;MSG-INTERVAL. (DO ((LINE REAL-START-LINE (LINE-NEXT LINE))) ((EQ LINE END-LINE)) (SETF (LINE-NODE LINE) *INTERVAL*)) (MOVE-BP START-BP END-LINE 0))) (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :AFTER :PARSE-MSG) (MSG -STATUS-) (send self :reformat-msg msg -status-)) (defmethod (babyl-mail-file-buffer :reformat-msg) (msg -status-) (OR (GET (LOCF OPTIONS) :|NO REFORMATION|) (GET -STATUS- 'REFORMATTED) (WHEN (AND (GET -STATUS- 'HEADERS-END-BP) *DEFAULT-REFORMATTING-TEMPLATE*) (UNLESS (TYPEP (FSYMEVAL *DEFAULT-REFORMATTING-TEMPLATE*) :COMPILED-FUNCTION) (COMPILE *DEFAULT-REFORMATTING-TEMPLATE*)) ;; First copy the original header. (INSERT-INTERVAL (FORWARD-LINE (INTERVAL-FIRST-BP (MSG-INTERVAL MSG)) -1) (INTERVAL-FIRST-BP (MSG-INTERVAL MSG)) (GET -STATUS- 'HEADERS-END-BP) T) (PUTPROP (LOCF (MSG-STATUS MSG)) T 'REFORMATTED) (SEND SELF :UPDATE-MSG-OPTIONS-IN-FILE MSG T) (FUNCALL *DEFAULT-REFORMATTING-TEMPLATE* (MSG-INTERVAL MSG) (LIST MSG))))) (defmethod (babyl-mail-file-buffer :after :new-msg) (msg) (send self :reformat-msg msg (assure-msg-parsed msg))) (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :NEW-HEADER-AND-TRAILER) () (VALUES " *** EOOH *** " #\NewLine)) ;; Our goal state is Return  Return text-of-next-message (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :UPDATE-MSG-END) (MSG &OPTIONAL FOR-APPEND-P) (LET ((END-LINE (BP-LINE (MSG-END-BP MSG))) (REAL-END-BP (MSG-REAL-END-BP MSG))) ;; Other mail file formats leave the end-bp and the real-end-bp on the same line. ;; Fix that. (WHEN (EQ END-LINE (BP-LINE REAL-END-BP)) (IF (MEMBER (LINE-PREVIOUS END-LINE) '(" " "")) (SETQ END-LINE (LINE-PREVIOUS END-LINE)) (INSERT-MOVING REAL-END-BP #\RETURN) (SETQ END-LINE (LINE-PREVIOUS (BP-LINE REAL-END-BP))))) (MOVE-BP (MSG-END-BP MSG) END-LINE 0) (SETF (LINE-LENGTH END-LINE) 0) (VECTOR-PUSH-EXTEND #\ END-LINE) (IF (NOT (AND (NOT FOR-APPEND-P) (EQ (BP-LINE REAL-END-BP) (BP-LINE LAST-BP)))) (VECTOR-PUSH-EXTEND #\Page END-LINE)))) (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :BEFORE :LOADING-DONE) (&AUX TEM) (AND (PLUSP (SETQ TEM (ARRAY-ACTIVE-LENGTH ARRAY))) (SEND SELF :UPDATE-MSG-END (AREF ARRAY (1- TEM))))) (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :BEFORE :SET-OPTIONS) (NEW-OPTIONS) (AND ( (GET (LOCF OPTIONS) :VERSION) (GET (LOCF NEW-OPTIONS) :VERSION)) (DOMSGS (MSG SELF) (SEND SELF :UPDATE-MSG-OPTIONS-IN-FILE MSG)))) (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :FIRST-MSG-BP) () (DO ((LINE (BP-LINE FIRST-BP) (LINE-NEXT LINE))) ((STRING-SEARCH #\ LINE) ;; If this used to standalone, assume about to have new messages (AND (= (LINE-LENGTH LINE) 1) (VECTOR-PUSH-EXTEND #\Page LINE)) (LET ((-NEXT- (LINE-NEXT LINE))) (IF -NEXT- (CREATE-BP -NEXT- 0) (CREATE-BP LINE (LINE-LENGTH LINE))))))) ;;; Handling of babyl status line at start of message. Format is: ;;; ::= "," "," ;;; ::= ( ",")* ;;; ::= ( ",")* (DEFUN PARSE-MSG-NEW-BABYL-STATUS-LINE (LINE STATUS &AUX KEYWORDS) (DO ((I 0 (1+ J)) (STATE 0) ;0 - reformatted, 1 - basic-labels, ;2 - user-labels (LEN (ARRAY-ACTIVE-LENGTH LINE)) (J) (STR) (TEM)) (( I LEN)) (OR (SETQ J (STRING-SEARCH-CHAR #\, LINE I LEN)) (RETURN)) (SETQ STR (SUBSTRING LINE I J)) ;; *** Temporary *** (AND (EQUALP STR "badHeader") (SETQ STR "bad-header")) ;; *** End Temporary (CASE STATE (0 (PUTPROP STATUS (NOT (STRING-EQUAL STR "0")) 'REFORMATTED) (SETQ STATE 1)) (1 (OR (SETQ TEM (CDR (ASS #'STRING-EQUAL STR *SAVED-INTERNAL-PROPERTIES-ALIST*))) (ZMAIL-ERROR "Bad status line ~A" LINE)) (PUTPROP STATUS T TEM)) (2 (COND ((NOT (SETQ TEM (ASS #'STRING-EQUAL STR *KEYWORD-ALIST*))) (SETQ TEM (INTERN (STRING-UPCASE STR) "")) (SETQ *KEYWORD-ALIST* (NCONC *KEYWORD-ALIST* (NCONS (CONS STR TEM))))) (T (SETQ TEM (CDR TEM)))) (PUSH TEM KEYWORDS))) (INCF J) (AND (= J LEN) (RETURN)) (CASE (CHAR LINE J) (#/, (AND (> (SETQ STATE (1+ STATE)) 2) (RETURN)) (SETQ J (1+ J))) (#/Space) (OTHERWISE (ZMAIL-ERROR "Bad status line ~A" LINE)))) (COND (KEYWORDS (SETQ KEYWORDS (NREVERSE KEYWORDS)) (PUTPROP STATUS KEYWORDS 'KEYWORDS) (PUTPROP STATUS (STRING-FROM-KEYWORDS KEYWORDS) 'KEYWORDS-STRING)))) (DEFMETHOD (BABYL-MAIL-FILE-BUFFER :UPDATE-MSG-OPTIONS-IN-FILE) (MSG &OPTIONAL NOPARSE &AUX MSG-STATUS BP LINE) (SETQ MSG-STATUS (IF NOPARSE (LOCF (MSG-STATUS MSG)) (ASSURE-MSG-PARSED MSG)) BP (MSG-REAL-START-BP MSG) LINE (BP-LINE BP)) (SETF (LINE-LENGTH LINE) 0) (FUNCALL (IF (< (GET (LOCF OPTIONS) :VERSION) 5) #'UPDATE-MSG-OLD-BABYL-STATUS-LINE #'UPDATE-MSG-NEW-BABYL-STATUS-LINE) LINE MSG-STATUS) (MUNG-BP-LINE-AND-INTERVAL BP)) (DEFUN UPDATE-MSG-NEW-BABYL-STATUS-LINE (LINE STATUS) (VECTOR-PUSH-EXTEND (IF (GET STATUS 'REFORMATTED) #\1 #\0) LINE) (VECTOR-PUSH-EXTEND #\, LINE) (DO ((LIST *SAVED-INTERNAL-PROPERTIES-ALIST* (CDR LIST)) (KEY)) ((NULL LIST)) (SETQ KEY (CDAR LIST)) (COND ((GET STATUS KEY) (VECTOR-PUSH-EXTEND #\SP LINE) (APPEND-TO-ARRAY LINE (CAAR LIST)) (VECTOR-PUSH-EXTEND #\, LINE)))) (VECTOR-PUSH-EXTEND #\, LINE) (DOLIST (KEYWORD (GET STATUS 'KEYWORDS)) (VECTOR-PUSH-EXTEND #\SP LINE) (APPEND-TO-ARRAY LINE (CAR (OR (RASSQ KEYWORD *KEYWORD-ALIST*) (RASS 'STRING-EQUAL KEYWORD *KEYWORD-ALIST*)))) (VECTOR-PUSH-EXTEND #\, LINE))) ;;; This is settable, but not in the standard way (DEFINE-NOT-SETTABLE-MAIL-FILE-OPTION :KEYWORDS) (DEFINE-NOT-SETTABLE-MAIL-FILE-OPTION :KEYWORDS-STRING) (DEFPROP :KEYWORDS PARSE-KEYWORDS-LIST BABYL-OPTION-PARSER) (DEFPROP :LABELS PARSE-KEYWORDS-LIST BABYL-OPTION-PARSER) (DEFUN PARSE-KEYWORDS-LIST (IGNORE STRING &OPTIONAL (START 0) END &AUX KEYWORDS-STRING KEYWORDS) (SETQ KEYWORDS-STRING (SUBSTRING STRING START END)) (DO ((I0 0 (1+ I1)) (I1) (I2) (STR)) (NIL) (OR (SETQ I0 (STRING-SEARCH-NOT-SET *WHITESPACE-CHARS* KEYWORDS-STRING I0)) (RETURN NIL)) (SETQ I1 (STRING-SEARCH-CHAR #\, KEYWORDS-STRING I0)) (AND (SETQ I2 (STRING-SEARCH-CHAR #\= KEYWORDS-STRING I0 I1)) (SETQ I0 (1+ I2))) (SETQ STR (SUBSTRING KEYWORDS-STRING I0 I1)) (PUSH (OR (ASS 'EQUALP STR *KEYWORD-ALIST*) (LET* ((KEY (INTERN (STRING-UPCASE STR) "")) (ELEM (CONS STR KEY))) (SETQ *KEYWORD-ALIST* (NCONC *KEYWORD-ALIST* (NCONS ELEM))) ELEM)) KEYWORDS) (OR I1 (RETURN NIL))) ;;Avoid writing out an empty labels line. (AND (NULL KEYWORDS) (SETQ KEYWORDS-STRING NIL)) `(:KEYWORDS ,(NREVERSE KEYWORDS) :KEYWORDS-STRING ,KEYWORDS-STRING)) ;;; This updates the string of all keywords at the head of the file ;;; The idea is that old keywords that are still valid are kept in the old order, and new ;;; ones appended at the end. (DEFUN (:KEYWORDS BABYL-OPTION-PRINTER) (STREAM IGNORE KEYWORDS PLIST &AUX STRING COMMA-FLAG) (SETQ STRING (MAKE-EMPTY-STRING 25.)) (LET ((KEYWORDS-STRING (GET PLIST :KEYWORDS-STRING))) (AND KEYWORDS-STRING (DO ((I0 0 (1+ I1)) (I1) (I2) (STR) (KEY) (ELEM)) (NIL) (SETQ I1 (STRING-SEARCH-CHAR #\, KEYWORDS-STRING I0) I2 (STRING-SEARCH-CHAR #\= KEYWORDS-STRING I0 I1) STR (SUBSTRING KEYWORDS-STRING (IF I2 (1+ I2) I0) I1) KEY (INTERN (STRING-UPCASE STR) "")) (COND ((SETQ ELEM (RASSQ KEY KEYWORDS)) (SETQ KEYWORDS (REMQ ELEM KEYWORDS)) (AND COMMA-FLAG (VECTOR-PUSH-EXTEND #\, STRING)) (SETQ COMMA-FLAG T) (APPEND-TO-ARRAY STRING KEYWORDS-STRING I0 I1))) (OR I1 (RETURN NIL))))) (DO ((AL KEYWORDS (CDR AL))) ((NULL AL)) (AND COMMA-FLAG (VECTOR-PUSH-EXTEND #\, STRING)) (SETQ COMMA-FLAG T) (APPEND-TO-ARRAY STRING (CAAR AL))) (PUTPROP PLIST STRING :KEYWORDS-STRING) (SEND STREAM :STRING-OUT (IF ( (GET PLIST :VERSION) 5) "Labels:" "Keywords:")) (SEND STREAM :STRING-OUT STRING)) ;;; *** BEGINNING OF OLD BABYL STUFF *** (DEFVAR *BABYL-BIT-MASK-PROPERTIES* '(REFORMATTED ;1 UNSEEN ;2 - really stored the other way LOSING-HEADERS ;4 ANSWERED ;10 FILED ;20 )) (DEFUN PARSE-MSG-OLD-BABYL-STATUS-LINE (LINE STATUS &AUX I) (COND ((= (AREF LINE (SETQ I 0)) #\D) (PUTPROP STATUS T 'DELETED) (SETQ I 1))) (DO ((BITS (LOGXOR (PARSE-NUMBER LINE I NIL 8) 2)) ;Check SEEN, not UNSEEN (L *BABYL-BIT-MASK-PROPERTIES* (CDR L)) (N 1 (LSH N 1))) ((NULL L)) (AND (BIT-TEST BITS N) (PUTPROP STATUS T (CAR L)))) (LET ((IDX (STRING-SEARCH-CHAR #\{ LINE))) (AND IDX (MULTIPLE-VALUE-BIND (KEYWORDS STRING) (PARSE-KEYWORDS LINE IDX) (PUTPROP STATUS KEYWORDS 'KEYWORDS) (PUTPROP STATUS STRING 'KEYWORDS-STRING))))) (DEFUN PARSE-KEYWORDS (LINE IDX &AUX (LENGTH (ARRAY-ACTIVE-LENGTH LINE)) KEYWORDS) (DO ((I0 IDX (STRING-SEARCH-CHAR #\{ LINE I1 LENGTH)) (I1) (STR) (KEY)) ((NULL I0)) (OR (SETQ I1 (STRING-SEARCH-CHAR #\} LINE (SETQ I0 (1+ I0)) LENGTH)) (RETURN NIL)) (SETQ STR (SUBSTRING LINE I0 I1) KEY (INTERN (STRING-UPCASE STR) "")) (OR (RASSQ KEY *KEYWORD-ALIST*) ;; Keywords not officially defined go at the end of the list (SETQ *KEYWORD-ALIST* (NCONC *KEYWORD-ALIST* (NCONS (CONS STR KEY))))) (PUSH KEY KEYWORDS)) (SETQ KEYWORDS (NREVERSE KEYWORDS)) (VALUES KEYWORDS (STRING-FROM-KEYWORDS KEYWORDS))) (DEFUN UPDATE-MSG-OLD-BABYL-STATUS-LINE (LINE STATUS &AUX (BITS 10000)) (DO ((L *BABYL-BIT-MASK-PROPERTIES* (CDR L)) (N 1 (LSH N 1))) ((NULL L)) (AND (GET STATUS (CAR L)) (SETQ BITS (LOGIOR BITS N)))) (FORMAT LINE "~O" (LOGXOR BITS 2)) ;Store SEEN, not UNSEEN (DOLIST (KEYWORD (GET STATUS 'KEYWORDS)) (FORMAT LINE " {~A}" (CAR (RASSQ KEYWORD *KEYWORD-ALIST*)))) (AND (GET STATUS 'DELETED) (ASET #\D LINE 0))) ;;; *** END OF OLD BABYL STUFF *** (DEFVAR *ZMAIL-BUFFER-SORT-ALIST* `(("None" :VALUE NIL) . ,*SORT-KEY-ALIST-1*)) (DEFINE-SETTABLE-MAIL-FILE-OPTION :SORT NIL :MENU-ALIST "Sort predicate" *ZMAIL-BUFFER-SORT-ALIST*) (DEFPROP :SORT MENU-ALIST-BABYL-OPTION-PARSER BABYL-OPTION-PARSER) (DEFPROP :SORT MENU-ALIST-BABYL-OPTION-PRINTER BABYL-OPTION-PRINTER) (DEFINE-SETTABLE-MAIL-FILE-OPTION :DELETE-EXPIRED NIL :MENU-ALIST "Delete expired messages" *YES-NO-ASK-ALIST*) (DEFPROP :DELETE-EXPIRED MENU-ALIST-BABYL-OPTION-PARSER BABYL-OPTION-PARSER) (DEFPROP :DELETE-EXPIRED MENU-ALIST-BABYL-OPTION-PRINTER BABYL-OPTION-PRINTER) (DEFUN MENU-ALIST-BABYL-OPTION-PARSER (TYPE STRING START) (LIST TYPE (IF (NULL START) T (DOLIST (ELEM (FOURTH (ASSQ TYPE *ZMAIL-BUFFER-OPTION-ALIST*))) (AND (STRING-EQUAL (CAR ELEM) STRING :START1 0 :START2 START) (RETURN (TV::MENU-EXECUTE-NO-SIDE-EFFECTS ELEM))))))) (DEFUN MENU-ALIST-BABYL-OPTION-PRINTER (STREAM TYPE VALUE IGNORE) (FORMAT STREAM "~:~:[: ~A~]" TYPE (EQ VALUE T) (NAME-FROM-MENU-VALUE VALUE (FOURTH (ASSQ TYPE *ZMAIL-BUFFER-OPTION-ALIST*))))) (DEFUN NAME-FROM-MENU-VALUE (VALUE ITEM-LIST) (DOLIST (ELEM ITEM-LIST) (AND (EQ (TV::MENU-EXECUTE-NO-SIDE-EFFECTS ELEM) VALUE) (RETURN (CAR ELEM))))) ;;; T(w)enex mail files. Each message has one status line of the form ;;; ,;bits. E.g. ;;; 30-Jan-81 16:53:05-EST,129;000000000001 (DEFFLAVOR TENEX-MAIL-FILE-MIXIN () () :ABSTRACT-FLAVOR (:REQUIRED-FLAVORS ZMAIL-DISK-BUFFER)) (DEFMETHOD (TENEX-MAIL-FILE-MIXIN :FORMAT-NAME) () "Tenex mail") (DEFMETHOD (TENEX-MAIL-FILE-MIXIN :HEADER-COMPATIBLE-MAIL-FILE-FORMATS) () '("Mail" "Rmail" "Babyl" "Tenex mail")) (DEFMETHOD (FS::TENEX-FAMILY-PATHNAME-MIXIN :MAIL-FILE-FORMAT-COMPUTER) (STREAM) (VALUES (IF (OR (NULL STREAM) (LET ((FIRST-LINE (SEND STREAM :LINE-IN))) (SEND STREAM :SET-POINTER 0) (STRING-EQUAL FIRST-LINE "Babyl Options:"))) ;; Babyl is the default when no stream since that is the filename ;; prompted. Perhaps this should be improved? 'BABYL-MAIL-FILE-BUFFER 'TENEX-MAIL-FILE-BUFFER) T)) ;Always APPEND-P (ADD-ZMAIL-BUFFER-FLAVOR 'TENEX-MAIL-FILE-BUFFER "Tenex") (DEFFLAVOR TENEX-MAIL-FILE-BUFFER () (TENEX-MAIL-FILE-MIXIN MAIL-FILE-BUFFER)) (DEFMETHOD (FS::TENEX-FAMILY-PATHNAME-MIXIN :POSSIBLE-MAIL-FILE-NAMES) () (LIST (SEND SELF :NEW-PATHNAME :NAME (STRING-UPCASE USER-ID) :TYPE "BABYL" :VERSION :NEWEST))) (DEFMETHOD (FS::TENEX-FAMILY-PATHNAME-MIXIN :POSSIBLE-MAIL-FILE-BUFFER-FLAVORS) () '(TENEX-MAIL-FILE-BUFFER BABYL-MAIL-FILE-BUFFER)) (DEFMETHOD (FS::TOPS20-PATHNAME-MIXIN :NEW-MAIL-PATHNAME) () (OR (MAYBE-OVERRIDDEN-MAIL-PATHNAME SELF) (SEND SELF :NEW-PATHNAME :NAME "MAIL" :TYPE "TXT" :VERSION 1))) (DEFMETHOD (FS::TENEX-PATHNAME-MIXIN :NEW-MAIL-PATHNAME) () (SEND SELF :NEW-PATHNAME :NAME "MESSAGE" :TYPE "TXT" :VERSION 1)) (DEFMETHOD (SI:HOST-TOPS20-MIXIN :DO-GMSGS) (STREAM) (MULTIPLE-VALUE-BIND (FILE-NAME UNAME-STRING) (SEND SELF :GMSGS-PATHNAME) (CONDITION-CASE (RESULT) (CHAOS:SIMPLE SELF (GMSGS-CONTACT-NAME FILE-NAME UNAME-STRING)) (SYS:NETWORK-ERROR (FORMAT *QUERY-IO* "~&GMSGS Error: ~A" (SEND RESULT :REPORT-STRING))) (:NO-ERROR (FORMAT STREAM "~&~A" (CHAOS:PKT-STRING RESULT)) (CHAOS:RETURN-PKT RESULT))) FILE-NAME)) (DEFMETHOD (SI:HOST-TOPS20-MIXIN :GMSGS-PATHNAME) () (VALUES (SEND (FS::USER-HOMEDIR SELF) :NEW-PATHNAME :NAME "ZMAIL" :TYPE "TXT") (FS::UNAME-ON-HOST SELF))) (DEFVAR *TENEX-BIT-MASK-PROPERTIES* '(UNSEEN ;1 - really the other way around DELETED ;2 ALWAYS-SHOW ;4 ANSWERED)) ;10 (DEFMETHOD (TENEX-MAIL-FILE-MIXIN :BEFORE :PARSE-MSG) (MSG -STATUS- &AUX LINE COMMA-POS SEMI-POS) (SETQ LINE (BP-LINE (MSG-REAL-START-BP MSG))) (COND ((AND (PLUSP (LINE-LENGTH LINE)) (SETQ COMMA-POS (STRING-SEARCH-CHAR #\, LINE)) (SETQ SEMI-POS (STRING-SEARCH-CHAR #\; LINE (1+ COMMA-POS)))) (PUTPROP -STATUS- (IGNORE-ERRORS (TIME::PARSE-UNIVERSAL-TIME LINE 0 COMMA-POS)) 'RECEIVED-DATE) (DO ((BITS (LOGXOR (PARSE-NUMBER LINE (1+ SEMI-POS) NIL 8) 1)) (L *TENEX-BIT-MASK-PROPERTIES* (CDR L)) (N 1 (LSH N 1))) ((NULL L)) (AND (BIT-TEST BITS N) (PUTPROP -STATUS- T (CAR L)))))) (MOVE-BP (MSG-START-BP MSG) (LINE-NEXT LINE) 0)) (DEFMETHOD (TENEX-MAIL-FILE-BUFFER :NEW-HEADER-AND-TRAILER) () (VALUES #\NewLine "")) (DEFMETHOD (TENEX-MAIL-FILE-BUFFER :UPDATE-MSG-OPTIONS-IN-FILE) (MSG &AUX -STATUS- BP LINE) (SETQ -STATUS- (ASSURE-MSG-PARSED MSG) BP (MSG-REAL-START-BP MSG) LINE (BP-LINE BP)) (SETF (LINE-LENGTH LINE) 0) (LET (DAY MONTH YEAR HOURS MINUTES SECONDS DST-P (BITS 0)) (MULTIPLE-VALUE (SECONDS MINUTES HOURS DAY MONTH YEAR NIL DST-P) (TIME::DECODE-UNIVERSAL-TIME (OR (CADR (GETL -STATUS- '(RECEIVED-DATE :DATE))) (TIME::GET-UNIVERSAL-TIME)) TIME::*TIMEZONE*)) (DO ((L *TENEX-BIT-MASK-PROPERTIES* (CDR L)) (N 1 (LSH N 1))) ((NULL L)) (AND (GET -STATUS- (CAR L)) (SETQ BITS (LOGIOR BITS N)))) (FORMAT LINE "~D-~A-~D ~D:~2,'0D:~2,'0D-~A,~D;~12,'0O" DAY (TIME::MONTH-STRING MONTH :SHORT) YEAR HOURS MINUTES SECONDS (TIME::TIMEZONE-STRING TIME::*TIMEZONE* DST-P) (COUNT-PDP-10-CHARS (MSG-START-BP MSG) (MSG-REAL-END-BP MSG) T) (LOGXOR BITS 1))) (MUNG-BP-LINE-AND-INTERVAL BP)) (DEFUN COUNT-PDP-10-CHARS (FROM-BP &OPTIONAL TO-BP IN-ORDER-P) (GET-INTERVAL FROM-BP TO-BP IN-ORDER-P) (LET ((FIRST-LINE (BP-LINE FROM-BP)) (FIRST-INDEX (BP-INDEX FROM-BP)) (LAST-LINE (BP-LINE TO-BP)) (LAST-INDEX (BP-INDEX TO-BP))) (COND ((EQ FIRST-LINE LAST-LINE) (- LAST-INDEX FIRST-INDEX)) (T (DO ((LINE (LINE-NEXT FIRST-LINE) (LINE-NEXT LINE)) (I 2 (+ 2 I (LINE-LENGTH LINE)))) ((EQ LINE LAST-LINE) (+ I (- (LINE-LENGTH FIRST-LINE) FIRST-INDEX) LAST-INDEX))))))) (DEFMETHOD (TENEX-MAIL-FILE-MIXIN :MAIL-FILE-REPARSABLE-P) () T) ;;; Messages on tenex has a byte count at the front ;;; The byte count can be screwed up by rubouts in the file ;;; turning themselves and the next character into a single LISPM character. (DEFMETHOD (TENEX-MAIL-FILE-MIXIN :LINE-END-OF-MSG-P) (LINE LENGTH STATE IGNORE START &AUX (ENTRY-STATE STATE)) (IF (AND STATE ( STATE LENGTH)) ;; Message ends after this line, or keeps going. (PROGN (SETQ STATE (- STATE (+ LENGTH 2))) (VALUES ( STATE 0) STATE)) ;; Message ends inside or in front of this line??? (LET* ((COMMA-IDX (%STRING-SEARCH-CHAR #\, LINE (OR STATE 0) LENGTH)) (SEMI-IDX (AND COMMA-IDX (%STRING-SEARCH-CHAR #\; LINE (1+ COMMA-IDX) LENGTH)))) (COND ((AND SEMI-IDX (SETQ STATE (PARSE-NUMBER LINE (1+ COMMA-IDX) SEMI-IDX 10. T))) ;; This line looks like a legitimate message starter. ;; Now take care of possibility that message ends in middle of line. (UNLESS (MEMQ ENTRY-STATE '(0 NIL)) (INSERT (CREATE-BP LINE ENTRY-STATE) #\RETURN) ;;Add two to the byte count of the message that is ending, ;;so that it will count the Return just inserted. (LET* ((START-COMMA-IDX (%STRING-SEARCH-CHAR #\, START 0 (LINE-LENGTH START))) (START-SEMI-IDX (AND START-COMMA-IDX (%STRING-SEARCH-CHAR #\; START (1+ START-COMMA-IDX) (LINE-LENGTH START)))) (START-COUNT (AND START-SEMI-IDX (PARSE-NUMBER START (1+ START-COMMA-IDX) START-SEMI-IDX 10. T)))) (WHEN START-COUNT (DELETE-INTERVAL (CREATE-BP START (1+ START-COMMA-IDX)) (CREATE-BP START START-SEMI-IDX) T) (INSERT (CREATE-BP START (1+ START-COMMA-IDX)) (FORMAT NIL "~d" (+ 2 START-COUNT)))))) (VALUES (NOT (NULL ENTRY-STATE)) STATE)) (T ;; If we cannot parse out a byte count on this line, ;; set the state to 1, which will make us look at each line ;; till we find one that looks semi-right. (VALUES NIL 1)))))) (DEFMETHOD (FS::TENEX-FAMILY-PATHNAME-MIXIN :INBOX-BUFFER-FLAVOR) () 'TENEX-INBOX-BUFFER) (DEFMETHOD (FS::TOPS20-PATHNAME-MIXIN :ZMAIL-TEMP-FILE-NAME) () (STRING-APPEND "_ZMAIL_" (SEND SELF :TYPE))) (DEFMETHOD (FS::TENEX-PATHNAME-MIXIN :ZMAIL-TEMP-FILE-NAME) () (STRING-APPEND "-ZMAIL-" (SEND SELF :TYPE))) (DEFFLAVOR TENEX-INBOX-BUFFER () (TENEX-MAIL-FILE-MIXIN INBOX-BUFFER)) ;;; Unix mail files. (DEFMETHOD (FS::UNIX-PATHNAME-MIXIN :MAIL-FILE-FORMAT-COMPUTER) (STREAM &AUX FLAVOR) (IF (NULL STREAM) (SETQ FLAVOR 'BABYL-MAIL-FILE-BUFFER) (LET ((FIRST-LINE (SEND STREAM :LINE-IN))) (SEND STREAM :SET-POINTER 0) (IF (STRING-EQUAL FIRST-LINE "Babyl Options:") ;; Looks like a babyl file (SETQ FLAVOR 'BABYL-MAIL-FILE-BUFFER) ;; Default is unix mail file (SETQ FLAVOR 'UNIX-MAIL-FILE-BUFFER)))) (VALUES FLAVOR T)) (DEFMETHOD (FS::UNIX-PATHNAME-MIXIN :POSSIBLE-MAIL-FILE-NAMES) () (LIST (SEND SELF :NEW-PATHNAME :NAME USER-ID :TYPE :BABYL :VERSION :NEWEST) (SEND SELF :NEW-PATHNAME :RAW-NAME "mbox" :TYPE :UNSPECIFIC :VERSION :NEWEST))) (DEFMETHOD (FS::UNIX-PATHNAME-MIXIN :POSSIBLE-MAIL-FILE-BUFFER-FLAVORS) () '(BABYL-MAIL-FILE-BUFFER UNIX-MAIL-FILE-BUFFER)) (DEFFLAVOR UNIX-MAIL-FILE-MIXIN () () :ABSTRACT-FLAVOR (:REQUIRED-FLAVORS ZMAIL-DISK-BUFFER)) (DEFMETHOD (UNIX-MAIL-FILE-MIXIN :FORMAT-NAME) () "Unix mail") (DEFMETHOD (UNIX-MAIL-FILE-MIXIN :MAIL-FILE-REPARSABLE-P) () T) (ADD-ZMAIL-BUFFER-FLAVOR 'UNIX-MAIL-FILE-BUFFER "Unix") (DEFFLAVOR UNIX-MAIL-FILE-BUFFER () (UNIX-MAIL-FILE-MIXIN MAIL-FILE-BUFFER)) (DEFCONST *UNIX-FROM-MARKER* "From ") (DEFMETHOD (UNIX-MAIL-FILE-BUFFER :UPDATE-MSG-OPTIONS-IN-FILE) (MSG) (LET* ((-STATUS- (ASSURE-MSG-PARSED MSG)) (OLD-FROM (FIRST (GET -STATUS- 'UNIX-FROM-HEADER))) (FROM (GET -STATUS- :FROM))) (OR (and (listp from) (listp old-from) (LOOP FOR X IN FROM AND Y IN OLD-FROM ALWAYS (LOOP FOR IND IN '(:NAME :HOST) ALWAYS (EQUAL (GET (LOCF X) IND) (GET (LOCF Y) IND))))) (LET* ((RECEIVED-DATE (GET -STATUS- 'RECEIVED-DATE)) (START-BP (MSG-START-BP MSG)) (LINE (BP-LINE START-BP))) (SETQ OLD-FROM (LIST FROM RECEIVED-DATE)) (IF (STRING-EQUAL-START LINE *UNIX-FROM-MARKER*) (SETF (LINE-LENGTH LINE) 0) (INSERT START-BP #\NewLine)) (WITH-OUTPUT-TO-STRING (-STREAM- LINE) (SEND -STREAM- :STRING-OUT *UNIX-FROM-MARKER*) (PRINT-ADDRESS-LIST FROM -STREAM-) (AND RECEIVED-DATE (MULTIPLE-VALUE-BIND (SECONDS MINUTES HOURS DAY MONTH YEAR DAY-OF-THE-WEEK) (TIME::DECODE-UNIVERSAL-TIME RECEIVED-DATE) (FORMAT -STREAM- " ~A ~A ~2D ~2,'0D:~2,'0D:~2,'0D ~D" (TIME::DAY-OF-THE-WEEK-STRING DAY-OF-THE-WEEK :SHORT) (TIME::MONTH-STRING MONTH :SHORT) DAY HOURS MINUTES SECONDS (+ YEAR 1900.))))))))) (DEFMETHOD (UNIX-MAIL-FILE-MIXIN :PARSE-MSG-TEXT) (MSG IGNORE &AUX UNIX-HEADER NEWSTAT) (LET ((START-BP (MSG-START-BP MSG))) (LET ((LINE (BP-LINE START-BP))) (COND ((STRING-EQUAL-START LINE *UNIX-FROM-MARKER*) (SETQ UNIX-HEADER (PARSE-UNIX-FROM-HEADER start-bp)) (PUTPROP (LOCF NEWSTAT) UNIX-HEADER 'UNIX-FROM-HEADER) (SETQ START-BP (BEG-LINE START-BP 1))))) (MULTIPLE-VALUE-BIND (TEM STOP-BP) (PARSE-HEADERS-INTERVAL START-BP (MSG-END-BP MSG) T T) (AND UNIX-HEADER (LET ((PLIST (LOCF TEM))) (PUTPROP PLIST (SECOND UNIX-HEADER) 'RECEIVED-DATE) (OR (GET PLIST :DATE) (PUTPROP PLIST (SECOND UNIX-HEADER) :DATE)) (OR (GET PLIST :FROM) (PUTPROP PLIST (FIRST UNIX-HEADER) :FROM)))) (VALUES (APPEND TEM NEWSTAT) STOP-BP)))) (DEFUN PARSE-UNIX-FROM-HEADER (start-bp &aux line (bp start-bp)) ;find the last line that has either "From" or ">From" (do () ((not (or (string-equal-start (bp-line bp) "From ") (string-equal-start (bp-line bp) ">From ")))) (setq bp (beg-line bp 1 nil))) (cond ((not (bp-= bp start-bp)) (setq bp (beg-line bp -1 t)) (setq line (bp-line bp))) (t ;couldn't make sense of what's going on, do the old behavior (setq line (bp-line start-bp)))) (LET ((START (STRING-LENGTH *UNIX-FROM-MARKER*)) END) (SETQ END (STRING-SEARCH-CHAR #\SP LINE START)) (DO (NEXT-END WORD) (()) ;; Look at the word (between spaces) following END. (OR (SETQ NEXT-END (STRING-SEARCH-CHAR #\SP LINE (1+ END))) (RETURN)) ;Don't get screwed by malformatted line, if we run out of it. (SETQ WORD (SUBSTRING LINE (1+ END) NEXT-END)) ;; If this word is a day-of-the-week abbreviation, ;; then it is not part of the sender, so use END, which points before it. (AND ( NEXT-END (+ END 4)) (DOLIST (DAYLIST TIME::*DAYS-OF-THE-WEEK*) (IF (STRING-EQUAL (CAR DAYLIST) WORD :START1 0 :START2 0 :END1 (LENGTH WORD)) (RETURN T))) (RETURN)) ;; Otherwise it is part of the sender. (SETQ END NEXT-END)) (LIST (condition-case (error) (PARSE-ADDRESSES LINE START END) (error (send error :report-string))) (AND END (CONDITION-CASE (ERROR) (TIME::PARSE-UNIVERSAL-TIME LINE (+ END 1) (string-search "remote" line)) (ERROR (SEND ERROR :REPORT-STRING))))))) ;; Copied from LAD: RELEASE-3.ZMAIL; MFHOST.LISP#66 on 2-Oct-86 03:04:07 (DEFMETHOD (UNIX-MAIL-FILE-MIXIN :LINE-END-OF-MSG-P) (LINE IGNORE STATE EOF IGNORE) (VALUES (COND ((NULL STATE) NIL) (EOF (LINE-LENGTH LINE)) ((and (STRING= LINE *UNIX-FROM-MARKER* :END1 (string-LENGTH *UNIX-FROM-MARKER*)) ;; These other tests are neccessary because, sometimes, a ``From'' ;; can appear at the beginning of a line (probably a Unix bug). (let ((start (string-search-char #\Space line (+ 1 (string-length *unix-from-marker*))))) (when start (dolist (daylist time::*days-of-the-week*) (let ((from (string-search (car daylist) line start))) ; quick d-o-w check (and from (string-search-set "0123456789" line ; quick date/numbers check (+ 1 from)) (return t))))))) :START-NEXT)) T)) (DEFMETHOD (UNIX-MAIL-FILE-MIXIN :REFORMAT-MSG-HEADER) (MSG) (WITH-BP (SEP (INTERVAL-FIRST-BP (MSG-INTERVAL MSG)) :MOVES) (LET ((STRM (INTERVAL-STREAM-INTO-BP (INTERVAL-FIRST-BP (MSG-INTERVAL MSG)))) (RECEIVED-DATE (GET (LOCF (MSG-STATUS MSG)) 'RECEIVED-DATE))) (SEND STRM :STRING-OUT *UNIX-FROM-MARKER*) (PRINT-ADDRESS-LIST (GET (LOCF (MSG-STATUS MSG)) :FROM) STRM) (AND RECEIVED-DATE (MULTIPLE-VALUE-BIND (SECONDS MINUTES HOURS DAY MONTH YEAR DAY-OF-THE-WEEK) (TIME::DECODE-UNIVERSAL-TIME RECEIVED-DATE) (FORMAT STRM " ~A ~A ~2D ~2,'0D:~2,'0D:~2,'0D ~D" (TIME::DAY-OF-THE-WEEK-STRING DAY-OF-THE-WEEK :SHORT) (TIME::MONTH-STRING MONTH :SHORT) DAY HOURS MINUTES SECONDS (+ YEAR 1900.)))) (DO ((TAIL (MSG-STATUS MSG) (CDDR TAIL))) ((NULL TAIL)) (WHEN (RASSQ (CAR TAIL) *HEADER-NAME-ALIST*) (PRINT-HEADER STRM (CADR TAIL) (CAR TAIL))))) (TERPRI STREAM) (DELETE-INTERVAL SEP (GET (LOCF (MSG-STATUS MSG)) 'HEADERS-END-BP)))) (DEFMETHOD (FS::UNIX-PATHNAME-MIXIN :INBOX-BUFFER-FLAVOR) () 'UNIX-INBOX-BUFFER) (defmethod (unix-mail-file-mixin :inbox-buffer) (&optional new-pathname delete-p) (let ((username (progn ;; Just causing a file access to the host to happen, so that we can get ;; the right user id. (fs::user-homedir (send pathname :host)) ;; We downcase the name because some Unix file servers are not case-sensitive ;; to the user name for the login command. (string-downcase (or (fs::uname-on-host (send pathname :host)) user-id))))) (make-inbox-buffer (send pathname :inbox-buffer-flavor) (if new-pathname (list (list new-pathname nil delete-p)) (loop for new-pathname in (list (send pathname :new-pathname :raw-directory '("usr" "spool" "mail") :raw-name username :type :unspecific :version :newest) (send pathname :new-pathname :raw-directory '("usr" "mail") :raw-name username :type :unspecific :version :newest) (send pathname :new-pathname :raw-name ".mail" :type :unspecific :version :newest)) collect (list new-pathname (send new-pathname :new-raw-type (send new-pathname :zmail-temp-file-name)) t))) self))) ;;; >> System V lossage here. (DEFMETHOD (FS::UNIX-PATHNAME-MIXIN :NEW-MAIL-PATHNAME) () (OR (MAYBE-OVERRIDDEN-MAIL-PATHNAME SELF) (SEND SELF :NEW-PATHNAME :RAW-DIRECTORY '("usr" "spool" "mail") :RAW-NAME USER-ID :TYPE :UNSPECIFIC :VERSION :NEWEST))) (DEFMETHOD (FS::UNIX-PATHNAME-MIXIN :ZMAIL-TEMP-FILE-NAME) () "zmail") (DEFFLAVOR UNIX-INBOX-BUFFER () (UNIX-MAIL-FILE-MIXIN INBOX-BUFFER)) (DEFMETHOD (UNIX-INBOX-BUFFER :BEFORE :PARSE-MSG) (MSG -STATUS-) MSG (PUTPROP -STATUS- T 'UNSEEN)) (DEFMETHOD (FS::VMS-PATHNAME-MIXIN :MAIL-FILE-FORMAT-COMPUTER) (STREAM &AUX FLAVOR) (IF (NULL STREAM) (SETQ FLAVOR 'BABYL-MAIL-FILE-BUFFER) (LET ((FIRST-LINE (SEND STREAM :LINE-IN))) (SEND STREAM :SET-POINTER 0) (IF (STRING-EQUAL FIRST-LINE #\FF) (SETQ FLAVOR 'VMS-MAIL-FILE-BUFFER) ;; Doesn't look like a vms file (SETQ FLAVOR 'BABYL-MAIL-FILE-BUFFER)))) (VALUES FLAVOR T)) (DEFMETHOD (FS::VMS-PATHNAME-MIXIN :POSSIBLE-MAIL-FILE-NAMES) () (LIST (SEND SELF :NEW-PATHNAME :NAME USER-ID :TYPE :BABYL :VERSION :NEWEST))) (DEFMETHOD (FS::VMS-PATHNAME-MIXIN :POSSIBLE-MAIL-FILE-BUFFER-FLAVORS) () '(BABYL-MAIL-FILE-BUFFER VMS-MAIL-FILE-BUFFER)) (DEFFLAVOR VMS-MAIL-FILE-MIXIN () () :ABSTRACT-FLAVOR (:REQUIRED-FLAVORS ZMAIL-DISK-BUFFER)) (DEFMETHOD (VMS-MAIL-FILE-MIXIN :FORMAT-NAME) () "VMS mail") (DEFMETHOD (VMS-MAIL-FILE-MIXIN :MAIL-FILE-REPARSABLE-P) () T) (ADD-ZMAIL-BUFFER-FLAVOR 'VMS-MAIL-FILE-BUFFER "VMS") (DEFFLAVOR VMS-MAIL-FILE-BUFFER () (VMS-MAIL-FILE-MIXIN MAIL-FILE-BUFFER)) (DEFMETHOD (VMS-MAIL-FILE-MIXIN :LINE-END-OF-MSG-P) (LINE LENGTH STATE EOFFLAG &REST IGNORE) (VALUES (COND ((NULL STATE) NIL) (EOFFLAG LENGTH) ((STRING-EQUAL LINE #\FF) :START-NEXT)) T)) (DEFMETHOD (VMS-MAIL-FILE-MIXIN :BEFORE :PARSE-MSG) (MSG &REST IGNORE) (LET ((REAL-START-LINE (BP-LINE (INTERVAL-FIRST-BP (MSG-REAL-INTERVAL MSG))))) (MOVE-BP (INTERVAL-FIRST-BP (MSG-INTERVAL MSG)) (LINE-NEXT REAL-START-LINE) 0) (SETF (LINE-NODE REAL-START-LINE) *INTERVAL*))) (DEFMETHOD (VMS-MAIL-FILE-MIXIN :AFTER :PARSE-MSG) (MSG &REST IGNORE) (LET ((LINE (LINE-PREVIOUS (BP-LINE (INTERVAL-LAST-BP (MSG-REAL-INTERVAL MSG)))))) (MOVE-BP (INTERVAL-LAST-BP (MSG-INTERVAL MSG)) LINE (LENGTH LINE)))) (DEFMETHOD (VMS-MAIL-FILE-MIXIN :NEW-HEADER-AND-TRAILER) () (VALUES (STRING-APPEND #\Page #\NewLine) #\NewLine)) (DEFMETHOD (VMS-MAIL-FILE-MIXIN :PARSE-MSG-TEXT) (MSG IGNORE &AUX VMS-HEADER NEWSTAT STOP-BP) (LET ((START-BP (MSG-START-BP MSG))) (LET ((LINE (BP-LINE START-BP)) (HOST (LIST (SEND (PATHNAME-HOST PATHNAME) :NAME)))) (SETQ VMS-HEADER (PARSE-VMS-FROM-HEADER LINE)) (PUTPROP (LOCF NEWSTAT) VMS-HEADER 'VMS-FROM-HEADER) (IF (EQUAL (FIRST VMS-HEADER) "CHAOSMAIL") (MULTIPLE-VALUE (NEWSTAT STOP-BP) (PARSE-HEADERS-INTERVAL (BEG-LINE START-BP 1) (MSG-END-BP MSG) T T)) (SETQ STOP-BP (BEG-LINE START-BP 1)) (WHEN (STRING-EQUAL (BP-LINE STOP-BP) "TO: " :END1 4 :END2 4) (LET ((TEM (PARSE-VMS-TO-HEADER (BP-LINE STOP-BP) HOST))) (WHEN TEM (PUTPROP (LOCF NEWSTAT) TEM :TO)) (SETQ STOP-BP (BEG-LINE STOP-BP 1)))) (WHEN (STRING-EQUAL (BP-LINE STOP-BP) "SUBJ: " :END1 6 :END2 6) (LET ((TEM (PARSE-VMS-SUBJECT-HEADER (BP-LINE STOP-BP)))) (WHEN TEM (PUTPROP (LOCF NEWSTAT) TEM :SUBJECT)) (SETQ STOP-BP (BEG-LINE STOP-BP 1))))) (LET ((PLIST (LOCF NEWSTAT))) (PUTPROP PLIST (SECOND VMS-HEADER) 'RECEIVED-DATE) (OR (GET PLIST :DATE) (PUTPROP PLIST (SECOND VMS-HEADER) :DATE)) (OR (GET PLIST :FROM) (PUTPROP PLIST (LIST (LIST :NAME (FIRST VMS-HEADER) :HOST HOST)) :FROM))) (VALUES NEWSTAT STOP-BP)))) (DEFUN PARSE-VMS-FROM-HEADER (LINE) (LET ((START (STRING-LENGTH "FROM: "))) (LIST (STRING-TRIM " " (SUBSTRING LINE START (+ START 12.))) (CONDITION-CASE (ERROR) (TIME::PARSE-UNIVERSAL-TIME LINE (+ START 12.) (STRING-SEARCH-CHAR #\SP LINE (1+ (STRING-SEARCH-CHAR #\SP LINE (+ START 12.)))) NIL) (ERROR (SEND ERROR :REPORT-STRING)))))) (DEFUN PARSE-VMS-TO-HEADER (LINE HOST &AUX COMMA TEM) (DO ((INDEX (STRING-LENGTH "TO: ")) (END (LENGTH LINE)) RCPTS) (( INDEX END) RCPTS) (SETQ COMMA (STRING-SEARCH-CHAR #\, LINE INDEX)) (SETQ TEM (STRING-TRIM " " (SUBSTRING LINE INDEX COMMA))) (UNLESS (EQUAL TEM "") (PUSH (LIST :NAME TEM :HOST HOST) RCPTS)) (IF COMMA (SETQ INDEX (1+ COMMA)) (RETURN RCPTS)))) (DEFUN PARSE-VMS-SUBJECT-HEADER (LINE) (SUBSTRING-AFTER-CHAR #\TAB LINE)) (DEFMETHOD (VMS-MAIL-FILE-MIXIN :REFORMAT-MSG-HEADER) (MSG) (WITH-BP (SEP (INTERVAL-FIRST-BP (MSG-INTERVAL MSG)) :MOVES) (LET ((STRM (INTERVAL-STREAM-INTO-BP (INTERVAL-FIRST-BP (MSG-INTERVAL MSG))))) (MULTIPLE-VALUE-BIND (NIL MINUTES HOURS DAY MONTH YEAR) (TIME::DECODE-UNIVERSAL-TIME (OR (GET (LOCF (MSG-STATUS MSG)) 'RECEIVED-DATE) (GET (LOCF (MSG-STATUS MSG)) :DATE))) (FORMAT STRM "From: CHAOSMAIL ~D-~A-~D ~2,'0D:~2,'0D~%" DAY (TIME::MONTH-STRING MONTH :SHORT) (+ 1900. YEAR) HOURS MINUTES)) (DO ((TAIL (MSG-STATUS MSG) (CDDR TAIL))) ((NULL TAIL)) (WHEN (RASSQ (CAR TAIL) *HEADER-NAME-ALIST*) (PRINT-HEADER STRM (CADR TAIL) (CAR TAIL))))) (TERPRI STREAM) (DELETE-INTERVAL SEP (GET (LOCF (MSG-STATUS MSG)) 'HEADERS-END-BP)))) (DEFMETHOD (FS::VMS-PATHNAME-MIXIN :NEW-MAIL-PATHNAME) () (OR (MAYBE-OVERRIDDEN-MAIL-PATHNAME SELF) (SEND SELF :NEW-PATHNAME :NAME "MAIL" :TYPE "MAI" :VERSION :NEWEST))) (DEFMETHOD (FS::VMS-PATHNAME-MIXIN :ZMAIL-TEMP-FILE-NAME) () "ZML") (DEFMETHOD (FS::VMS-PATHNAME-MIXIN :INBOX-BUFFER-FLAVOR) () 'VMS-INBOX-BUFFER) (DEFFLAVOR VMS-INBOX-BUFFER () (VMS-MAIL-FILE-MIXIN INBOX-BUFFER)) (DEFMETHOD (VMS-INBOX-BUFFER :BEFORE :PARSE-MSG) (MSG -STATUS-) MSG (PUTPROP -STATUS- T 'UNSEEN))