@X @~
~V7 56 2 -5
~D10
~H                    MUSS
~
~
~D10
~H            LIB131
~D10
~MMANCHESTER UNIVERSITY  -  CONFIDENTIAL
~
~
                                                             ISSUE 11~
~V9 -1
~P
~V9 -1
~YLIB131
~Y
~V9 -1
~P
~V9 -1
~D15
~HFLOWCHARTS
~
~
~H               LIB131
~V9 -1
~F
@TITLE LIB13/1(1,10)
@COL 1S
@FLOW 1
@BOX 1.0
EXTERNAL ENVIRONMENT
@BOX 1.1
::EXTERNAL ENVIRONMENT
LSPEC NAMES ();
LSPEC LOOK.UP.PROCESS (LOGICAL64, LOGICAL64);
LSPEC OUT.HEX (LOGICAL32, INTEGER)
LSPEC OUT.NAME (LOGICAL64)
LSPEC TIME.AND.DATE ();
LSPEC DEFINE.INPUT (INTEGER, ADDR [LOGICAL8], INTEGER, INTEGER) / INTEGER;
LSPEC DEFINE.IO (INTEGER, ADDR [LOGICAL8], ADDR [LOGICAL8], INTEGER, INTEGER, IN
TEGER, INTEGER) / INTEGER;
LSPEC O.BPOS () / INTEGER;
LSPEC O.POS() / INTEGER;
LSPEC OUT.TD (LOGICAL64, INTEGER);
LSPEC SPACES (INTEGER);
LSPEC SELECT.INPUT (INTEGER);
LSPEC BREAK.INPUT (INTEGER);
LSPEC IN.BIN.B () / INTEGER;
LSPEC OUT.BIN.B (INTEGER);
LSPEC SET.O.BPOS (INTEGER, INTEGER);
LSPEC SET.I.BPOS (INTEGER, INTEGER);
LSPEC IN.STR (ADDR [LOGICAL8]) / INTEGER;
LSPEC OUT.HDR (ADDR [LOGICAL8]);
LSPEC I.ENQ () / INTEGER;
LSPEC OUT.DATE ();
LSPEC BREAK.OUTPUT (INTEGER);
LSPEC SELECT.OUTPUT (INTEGER);
LSPEC END.OUTPUT (INTEGER, INTEGER);
LSPEC OUT.I (INTEGER, INTEGER);
LSPEC CAPTION (ADDR [LOGICAL8]);
LSPEC NEW.LINES (INTEGER);
LSPEC OUT.CH (INTEGER);
LSPEC IN.CH () / INTEGER;
LSPEC NEXT.CH () / INTEGER;
LSPEC SKIP.LINE ();
LSPEC PROMPT (ADDR [LOGICAL8]);
LSPEC SET.CH.STATUS (INTEGER, INTEGER, INTEGER, INTEGER);
@END
/P/
@TITLE LIB13(1,10)
@COL 1S-2R-3N-4R-5R-6F
@FLOW 1-2-3-4-5-6
@BOX 1.0
MAIL SENDING, READING & DISPOSAL MODULE.
@BOX 4.0
PROCEDURES IN MODULE
1 MAIL
2 DELETE MAIL
3 READ MAIL
4 COPY.TO.START
@BOX 6.0
END
@BOX 1.1
#LIB13/1
MODULE SEND (MAIL, READ.MAIL, DELETE.MAIL);
@BOX 4.1
LSPEC MAIL ();
LSPEC DELETE.MAIL (ADDR [LOGICAL8]);
LSPEC READ.MAIL (ADDR [LOGICAL8]);
PSPEC COPY.TO.START (ADDR [LOGICAL8]);
#LIB13.1
#LIB13.2
#LIB13.3
#LIB13.4
@BOX 6.1
*END
@END
/P/
@TITLE LIB13.1(1,10)
@COL 1S-2R-3R-4N-5R-6R-7T-8R-9F
@COL 10N-11R
@FLOW 1-2-3-4-5-6-7N-8-9
@FLOW 7YES-11-10-4
@ROW 4-10
@ROW 8-11
@BOX 1.0
MAIL
@BOX 2.0
FIND THE TIME AND DATE.
SET UP DUMMY OUTPUT STREAM
@BOX 3.0
OUTPUT THE MESSAGE ID, TIME & DATE
TO BOTH THE MESSAGE AND THE TERMINAL
INPUT THE SENDER AND DESTINATION,
ENTERING THEM INTO THE MESSAGE.
@BOX 5.0
STORE THE DESTINATION MACHINE
@BOX 6.0
(IF FIRST TIME ROUND THIS LOOP
READ THE REST OF THE HEADER AND
MESSAGE).
SEND THE NEXT COPY OF THE MESSAGE
@BOX 7.0
ARE THERE ANY MORE COPIES TO SEND ?
@BOX 8.0
TIDY UP BEFORE FINISHING
@BOX 9.0
END
@BOX 11.0
SET THE FLAG TO SHOW IT IS NOT
THE FIRST COPY BEING SENT
@BOX 1.1
PROC MAIL;
INTEGER I, OUTPUT.CHANNEL, KEY.INDEX, WORD, INDEX;
LOGICAL8 [225] NAME.ARRAY, MACHINE.ARRAY;
LOGICAL8 FOUND, KEYWRD, ACTN.FLAG,
   ERROR, FIRST.COPY, C.CHAR;
LOGICAL64 MACHINE, TD;
PSPEC COMMENT ();
PSPEC MULTSPACE ();
PSPEC TELL.USER (INTEGER);
PSPEC  READIN ();
PSPEC READ.ENTRY (ADDR [LOGICAL8]);
#LIB13.1.1
#LIB13.1.2
#LIB13.1.3
#LIB13.1.4
#LIB13.1.5
@BOX 2.1
TIME.AND.DATE ();
PWW1 => TD;
DEFINE.INPUT (5, %"*", %3C8, 0);
DEFINE.IO (-1,%"SCR*", %"*", 0, 64, 1, 0) => OUTPUT.CHANNEL;
"Y" => FIRST.COPY;
@BOX 3.1
"Y" => FIRST.COPY;
"X" => ACTN.FLAG;
#LIB13.1.7
#LIB13.1.8
-1 => INDEX;
READ.ENTRY (%"SENDER: ");
-1 => INDEX;
READ.ENTRY (%"TO: ");
@BOX 5.1
0 => MACHINE;
FOR I < MACHINE.ARRAY [INDEX * 9] DO
   MACHINE <<- 8 => MACHINE;
   MACHINE.ARRAY [INDEX * 9 + I + 1] !> MACHINE;
OD
@BOX 6.1
#LIB13.1.6
@BOX 7.1
IF INDEX > -1
@BOX 8.1
SO (0);
SI (0);
END.OUTPUT (OUTPUT.CHANNEL, 0);
@BOX 9.1
END
@BOX 11.1
"N" => FIRST.COPY;
@END
/P/
@TITLE LIB13.1.1(1,10)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
COMMENT
@BOX 2.0
PROCESS COMMENTS
@BOX 3.0
END
@BOX 1.1
PROC COMMENT;
@BOX 2.1
WHILE NEXT.CH () /= ")" DO
   OUT.CH (IN.CH ());
OD
OUT.CH (IN.CH ());
@BOX 3.1
END
@END
/P/
@TITLE LIB13.1.2(1,10)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
MULTSPACE;
@BOX 2.0
DISPOSES OF MULTIPLE SPACES
@BOX 3.0
END
@BOX 1.1
PROC MULTSPACE;
@BOX 2.1
WHILE NEXT.CH () = " " DO
   IN.CH ();
OD
@BOX 3.1
END
@END
/P/
@TITLE LIB13.1.3(1,10)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
TELL.USER (CAP.NO)
@BOX 2.0
OUTPUT THE REQUIRED MESSAGE TO THE TERMINAL
@BOX 3.0
END
@BOX 1.1
PROC TELL.USER (CAP.NO);
INTEGER I, J, TEMP;
DATAVEC STRING (LOGICAL8)
   "SPACE EXPECTED"
   "< EXPECTED"
   "EXTRA CHARACTERS IGNORED"
   "< USER @ MACHINE > EXPECTED"
   "UNABLE TO DELIVER TO "
   "DELIVERED TO "
   "TOO MANY DESTINATIONS"
   "INVALID <"
   "KEYWORD EXPECTED"
   "ENTER MESSAGE"
END
DATAVEC STARTS (INTEGER)
   0 14 24 48 75 96 109 130 139 155 169
END
@BOX 2.1
SELECT.OUTPUT (0);
CAPTION (PART (^STRING, STARTS [CAP.NO], STARTS [CAP.NO + 1] - 1));
IF CAP.NO = 5 OR CAP.NO = 4 THEN
   INDEX * 9 + 1 => TEMP;
   CAPTION (PART (^NAME.ARRAY, TEMP, TEMP + NAME.ARRAY [TEMP - 1] - 1 ));
FI
NEW.LINES (1);
SELECT.OUTPUT (OUTPUT.CHANNEL);
@BOX 3.1
END
@END
/P/
@TITLE LIB13.1.4(1,10)
@COL 5R
@COL 1S-2N-3R-4T-6T-7R-8T-9R-10F
@COL 34N-11R
@ROW 5-6
@ROW 9-11
@ROW 2-34
@FLOW 1-2-3-4NO-6NO-7-8NO-9-10
@FLOW 4YES-5-9
@FLOW 6YES-11-34-2
@FLOW 8YES-11
@BOX 1.0
READIN
@BOX 3.0
STORE STARTING POINT FOR OUTPUT.
ADD < TO MESSAGE.
READ IN DESTINATION USER ID AND
ADD THIS TO THE END OF NAME.ARRAY
AND ALSO TO THE MESSAGE.
@BOX 4.0
IS IT A > NEXT ?
@BOX 5.0
ENTER 0 AS THE MACHINE
@BOX 6.0
WAS IT NOT @ OR "AT" ?
@BOX 7.0
ENTER @ INTO MESSAGE
READ NEXT STRING,  STORE IT
AS THE DESTINATION MACHINE AND
ENTER IT INTO THE MESSAGE

@BOX 8.0
IS THE NEXT ITEM OF INPUT NOT > ?
@BOX 9.0
IF PART OF Bcc:, RESET INPUT POINTER TO MESSAGE,
BACK TO THE STORED STARTING POINT, OTHERWISE
PUT > INTO MESSAGE.
READ NEXT CHARACTER
@BOX 10.0
END
@BOX 11.0
REMOVE DESTINATION FROM LIST
GIVE ERROR MESSAGE
@BOX 1.1
PROC READIN;
INTEGER I;
INTEGER32 LPSN, BPSN;
@BOX 3.1
1 +> INDEX;
"N" => ERROR;
O.BPOS () => BPSN;
O.POS () => LPSN;
CAPTION (%"< ");
MULTSPACE ();
1 => I;
WHILE NEXT.CH () /= "@" /= " " /= "$L" /= ">" DO
   OUT.CH (IN.CH() => NAME.ARRAY [9 * INDEX + I]);
      1 +> I;
OD
I - 1 => NAME.ARRAY[9 * INDEX];
MULTSPACE ();
@BOX 4.1
IF NEXT.CH () = ">"
@BOX 5.1
0 => MACHINE.ARRAY [INDEX * 9];
IN.CH () => C.CHAR;
@BOX 6.1
IF IN.CH () => C.CHAR /= "@" AND
   [C.CHAR /= "A" OR NEXT.CH () /= "T"]
@BOX 7.1
CAPTION (%" @ ");
MULTSPACE ();
1 => I;
WHILE NEXT.CH () /= " " /= "$L" /= ">" DO
   OUT.CH (IN.CH () => MACHINE.ARRAY [INDEX * 9 + I]);
1 +> I;
OD
I - 1 => MACHINE.ARRAY [INDEX * 9];
WHILE IN.CH () => C.CHAR = " " DO OD
@BOX 8.1
IF C.CHAR /= ">"
@BOX 9.1
IF ACTN.FLAG = "B" THEN
   SET.O.BPOS (BPSN, LPSN);
ELSE
   CAPTION (%" >");
FI
IN.CH () => C.CHAR;
@BOX 10.1
END
@BOX 11.1
TELL.USER (3);
WHILE IN.CH() => C.CHAR /= "<" DO OD
SET.O.BPOS (BPSN, LPSN);
@END
/P/
@TITLE LIB13.1.5(1,10)
@COL 1S-2R-9N-3R-4T-6F
@COL 7N-5R
@ROW 9-7
@FLOW 1-2-9-3-4NO-6
@FLOW 4YES-5-7-9
@ROW 6-5
@BOX 1.0
READ ENTRY (ENTRY)
@BOX 2.0
STORE INPUT POINTER TO THE MESSAGE
@BOX 3.0
USE THE STRING PASSED AS ENTRY FOR
PROMPTING AND ALSO ENTER IT INTO
THE MESSAGE.
READ IN THE REPLY.
@BOX 4.0
WAS THERE AN ERROR ?
@BOX 5.0
SET THE INPUT POINTER BACK TO THE
STORED VALUE READY TO TRY AGAIN.
@BOX 6.0
END
@BOX 1.1
PROC READ.ENTRY (ENTRY);
INTEGER32 LINE.POS, BYTE.POS;
@BOX 2.1
O.BPOS () => BYTE.POS;
O.POS () => LINE.POS;
@BOX 3.1
SELECT.OUTPUT (OUTPUT.CHANNEL);
PROMPT (ENTRY);
CAPTION (ENTRY);
#LIB13.1.5.1
@BOX 4.1
IF ERROR = "Y"
@BOX 5.1
SET.O.BPOS (BYTE.POS, LINE.POS);
@BOX 6.1
END
@END
/P/
@TITLE LIB13.1.5.1(1,10)
@COL 1S-2R-3T-4R-5R-6F
@FLOW 1-2-3YES-5-6
@FLOW 3NO-4-5
@BOX 1.0
BEGIN
@BOX 2.0
READ CHARACTERS TYPED INTO MESSAGE UNTIL < IS FOUND.
READ IN DESTINATION AND ENTER IT INTO THE MESSAGE.
@BOX 3.0
WAS THERE AN ERROR READING THE DESTINATION ?
@BOX 4.0
READ IN AND ENTER INTO THE MESSAGE, ANY FURTHER
LEGAL ITEMS ON THE LINE.
@BOX 5.0
CHECK FOR END OF LINE
IF IT ISN'T THE NEXT CHARACTER
SKIP UNTIL FOUND AND NOTIFY THE
USER.
ENTER NEW LINE INTO THE MESSAGE.
@BOX 6.0
END
@BOX 1.1
BEGIN
PSPEC PROC.TYPE ();
PROC PROC.TYPE;
END
PSPEC SYNTAX (ADDR PROC.TYPE, ADDR LOGICAL8);
#LIB13.1.5.1.1
ADDR PROC.TYPE CALL.PROC;
DATAVEC PROC.CALL (ADDR PROC.TYPE)
   MULTSPACE
   MULTSPACE
   COMMENT
   MULTSPACE
   MULTSPACE
END
DATAVEC MATCH (LOGICAL8)
   "$L " "(" "$L "
END
@BOX 2.1
IN.CH () => C.CHAR;
PROMPT (%"->");
SYNTAX (PROC.CALL [0], ^MATCH [1]);
IF C.CHAR /= "<" THEN
   WHILE C.CHAR  /= "("  /= "<" DO
      OUT.CH (C.CHAR);
      IN.CH () => C.CHAR;
   OD
FOR I < 5 DO
   SYNTAX (PROC.CALL [I], ^MATCH [I]);
OD
FI
IF C.CHAR  = "<" THEN
   READIN ();
ELSE
   "Y" => ERROR;
   TELL.USER (1);
FI
@BOX 3.1
IF ERROR = "Y"
@BOX 4.1
SYNTAX (PROC.CALL [0], ^MATCH [1]);
SYNTAX (PROC.CALL [2], ^MATCH [2]);
@BOX 5.1
IF   C.CHAR /= %A THEN
   TELL.USER (2);
   SKIP.LINE ();
ELSE
   OUT.CH (C.CHAR);
FI
@BOX 6.1
END
@END
/P/
@TITLE LIB13.1.5.1.1(1,10)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
SYNTAX (PROCEDURE, CH)
@BOX 2.0
IF THE LAST CHARACTER READ MATCHES THE TEST CHARACTER
PASSED TO THIS PROCEDURE, ENTER IT INTO THE MESSAGE
CALL THE PROCEDURE PASSED, AND READ THE NEXT CHARACTER
@BOX 3.0
END
@BOX 1.1
PROC SYNTAX (PROCEDURE, CH);
@BOX 2.1
IF CH^ = C.CHAR THEN
   OUT.CH (C.CHAR);
   PROCEDURE^ ();
   IN.CH () => C.CHAR;
FI
@BOX 3.1
END
@END
/P/
@TITLE LIB13.1.6(1,10)
@COL 14R-15N
@COL 1S-2R-3T-4R-5R-6R-19N-7R
-8T-9T-10R-17N-11R-12F
@COL 18N-13R-16N
@FLOW 1-2-3NO-4-5-6-19-7-8NO-9NO-10-17-11-12
@ROW 18-19
@ROW  9-14
@ROW 16-17
@ROW 13-10
@ROW 17-15
@FLOW 3YES-14-15-17
@FLOW 8YES-14
@FLOW 9YES-13-16-18-19
@BOX 1.0
ENTER THE REST OF THE MESSAGE IF NOT YET COMPLETE
AND SEND COPY
BEGIN
@BOX 2.0
LOOK UP PROCESS TO CHECK IF
IT IS POSSIBLE TO SEND TO THAT DESTINATION
@BOX 3.0
DOES THE PROCESS NOT EXIST ?
@BOX 4.0
IF IT IS THE FIRST COPY TO BE SENT
READ IN THE REST OF THE MESSAGE.
@BOX 5.0
SEND  COPY TO THE DELIVERING PROCESS.
@BOX 6.0
GET READY FOR THE REPLY
@BOX 7.0
EXTRACT THE ANSWER.
@BOX 8.0
DOES IT SAY THE OTHER PROCESS
COULD NOT DELIVER ?
@BOX 9.0
IS IT AN UNAPPROPRIATE ANSWER ?
@BOX 10.0
INFORM USER THAT THE MAIN COPY
HAS BEEN SENT
@BOX 11.0
SELECT NEXT DESTINATION
@BOX 12.0
END
@BOX 13.0
THROW AWAY MESSAGE.
@BOX 14.0
INFORM USER THAT THE MESSAGE
COULD NOT BE DELIVERED
@BOX 1.1
BEGIN
LOGICAL8 ANSWER.RECEIVED, CHAR.BEFORE;
INTEGER REAL.MESS.CHANNEL;
@BOX 2.1
LOOK.UP.PROCESS ("MAIL", MACHINE);
@BOX 3.1
IF PW0 /= 0
@BOX 4.1
IF FIRST.COPY = "Y" THEN
   #LIB13.1.6.1
FI
@BOX 5.1
#LIB13.1.6.2
@BOX 6.1
SET.CH.STATUS (5, 1, 0, 0);
SELECT.INPUT (5);
@BOX 7.1
FOR I < 7 DO
   IN.CH () => ANSWER.RECEIVED;
OD
@BOX 8.1
IF ANSWER.RECEIVED = "N"
@BOX 9.1
IF ANSWER.RECEIVED /= "Y"
@BOX  10.1
   TELL.USER (5);
@BOX 11.1
1 -> INDEX;
@BOX  12.1
END
@BOX 13.1
BREAK.INPUT (5);
@BOX  14.1
TELL.USER (4);
#LIB13.1.6.3
@END
/P/
@TITLE LIB13.1.6.1(1,10)
@COL 1S-2R-3R-9N-4R-5T-6R-8F
@COL 10N-7R
@FLOW 1-2-3-9-4-5N-6-8
@FLOW 5Y-7-10-9
@ROW 6-7
@ROW 9-10
@BOX 1.0
READ IN REST OF MESSAGE.
BEGIN
@BOX 2.0
READ IN REST OF HEADER.
@BOX 3.0
ENTER NEWLINE INTO MESSAGE
@BOX 4.0
READ IN MESSAGE UNTIL @ MARKS THE END
OR "%" FOUND
@BOX 5.0
WAS A "%" FOUND ?
@BOX 6.0
GET RID OF THE LINE FEED AND ANYTHING ELSE FOLLOWING
THE @.
@BOX 7.0
READ IN NEXT CHARACTER AND
DEAL WITH REQUEST FOR FILE
@BOX 8.0
END
@BOX 1.1
BEGIN
@BOX 2.1
#LIB13.1.6.1.1
@BOX 3.1
OUT.CH ("$L");
@BOX 4.1
WHILE C.CHAR /= "$L" OR  NEXT.CH () /= "@" /= "%" DO
   IN.BIN.B () => C.CHAR;
   OUT.BIN.B (C.CHAR);
OD
@BOX 5.1
IF NEXT.CH () = "%"
@BOX 6.1
SKIP.LINE ();
@BOX 7.1
IN.CH () => C.CHAR;
#LIB13.1.6.1.2
@BOX 8.1
END
@END
/P/
@TITLE LIB13.1.6.1.1(1,10)
@COL 1S-2R-10N-3R-4T-6R-7T-8R-11F
@COL 9N-5R
@FLOW 1-2-10-3-4NO-6-7NO-8-11
@FLOW 4YES-5-9-10
@FLOW 7YES-3
@ROW 10-9
@ROW 6-5
@BOX 1.0
BEGIN
@BOX 2.0
LOOK FOR NEXT KEYWORD OR END OF HEADER
IF A SPACE IS FOUND FIRST TELL USER
KEYWORD EXPECTED.
@BOX 3.0
IDENTIFY KEYWORD
@BOX 4.0
IS THE WORD NOT A VALID KEYWORD, BUT ENDING WITH :
AND STARTING AT THE START OF A LINE.
@BOX 5.0
TELL USER INVALID KEYWORD
@BOX 6.0
TAKE APPROPRIATE ACTION FOR THAT KEYWORD
@BOX 7.0
IS IT THE END OF THE HEADER ?
@BOX 8.0
TELL USER TO ENTER MESSAGE
@BOX 11.0
END
@BOX 1.1
BEGIN
DATAVEC KEYWORDS (LOGICAL8)
   "Bcc:"
   "COMMENT:"
   "FROM:"
   "IN-REPLY-TO:"
   "POSTAL:"
   "REPLY-TO:"
   "SPECIAL(ACTION):"
   "SPECIAL(INFO):"
   "SUBJECT:"
   "cc:"
END
@BOX 2.1
"X" => ACTN.FLAG;
WHILE [C.CHAR /= %A OR NEXT.CH () /= %A] AND
   C.CHAR /= ":" /= " " DO
   OUT.CH (C.CHAR);
   IN.CH () => C.CHAR;
OD
IF C.CHAR = " " THEN
   TELL.USER (8);
   SKIP.LINE ();
FI
@BOX 3.1
#LIB13.1.6.1.1.1
   @BOX 4.1
   IF FOUND /= "Y" AND KEYWRD = "Y"
   AND CHAR.BEFORE = "$L"
   @BOX 5.1
      TELL.USER (8);
      IN.CH () => C.CHAR;
   @BOX 6.1
   IF KEYWRD = "Y" AND FOUND = "Y" THEN
      IF WORD = 0 THEN
         "B" => ACTN.FLAG;
         SET.O.BPOS ( O.BPOS () -5, O.POS ());
      ELSE
        IF WORD = 9 THEN
           "C" =>ACTN.FLAG;
        ELSE
           "X" => ACTN.FLAG;
           IF WORD /= 1 /= 2 /= 5 THEN
           ELSE
              WHILE C.CHAR /= ":" AND [C.CHAR /= %A OR NEXT.CH () /= %A] DO
                 OUT.CH (C.CHAR);
                 IN.CH () => C.CHAR;
              OD
           FI
        FI
     FI
      IF C.CHAR /= ":" THEN
         IN.CH () => C.CHAR;
      FI
   FI
   @BOX 7.1
   IF C.CHAR /= %A OR NEXT.CH () /= %A
   @BOX 8.1
TELL.USER (9);
@BOX 11.1
   END;
@END
@TITLE LIB13.1.6.1.1.1(1,10)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BEGIN
@BOX 2.0
READ IN HEADER IDENTIFYING COMMENTS.
DEAL WITH EXTRA DESTINATIONS UNDER Bcc:
AND cc: AND IDENTIFY KEYWORDS.
@BOX 3.0
END
@BOX 1.1
BEGIN
INTEGER B.INDEX, L.INDEX;
@BOX 2.1
WHILE [C.CHAR /= %A OR NEXT.CH () /= %A] AND C.CHAR /= "<" /= ":" DO
   IF C.CHAR = "(" THEN
      COMMENT ();
   ELSE
      OUT.CH (C.CHAR);
   FI
   IN.CH () => C.CHAR;
OD
IF C.CHAR = "<" THEN
   IF [ACTN.FLAG = "C" OR ACTN.FLAG = "B"] THEN
      IF INDEX < 24 THEN
         READIN ();
      ELSE
         TELL.USER (6);
      FI
   ELSE
      TELL.USER (7);
      WHILE IN.CH () /= ">" DO OD
      IN.CH () => C.CHAR;
   FI
FI
IF C.CHAR = ":" THEN
   "Y" => KEYWRD;
   OUT.CH (C.CHAR);
   O.BPOS () => B.INDEX;
   O.POS () => L.INDEX;
   SELECT.INPUT (OUTPUT.CHANNEL);
   WHILE IN.CH () => CHAR.BEFORE /= "$L" /= " " DO
      SET.I.BPOS (1 -> B.INDEX, L.INDEX);
   OD
   IF NEXT.CH () = " " OR NEXT.CH () = "$L" THEN
      IN.CH  ();
   FI
   O.BPOS () => B.INDEX;
   O.POS () => L.INDEX;
   "N" => FOUND;
   -1 => KEY.INDEX;
   0 => WORD;
   WHILE [IN.CH () => C.CHAR >= KEYWORDS [1 +> KEY.INDEX]]
      AND FOUND /= "Y" AND WORD < 10 DO
      WHILE ":" /=  C.CHAR AND KEYWORDS [KEY.INDEX] = C.CHAR DO
         1 +> KEY.INDEX;
         IN.CH () => C.CHAR;
      OD
      IF KEYWORDS [KEY.INDEX] = C.CHAR = ":" THEN
        "Y" => FOUND;
      FI
      IF FOUND /= "Y" THEN
         IF KEYWORDS [KEY.INDEX] /= ":" THEN
            WHILE KEYWORDS [1 +> KEY.INDEX] /= ":" DO OD
         FI
         1 +> WORD;
         SET.I.BPOS (B.INDEX, L.INDEX);
      FI
   OD
ELSE
   "N" => KEYWRD;
FI
SELECT.INPUT (0);
@BOX 3.1
END
@END
/P/
@TITLE LIB13.1.6.1.2(1,10)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BEGIN
@BOX 2.0
COPY REQUIRED FILE INTO MESSAGE
@BOX 3.0
END
@BOX 1.1
BEGIN
INTEGER NUMBER, OUT.CHANNEL, IN.CHANNEL;
LOGICAL8 [17] F.NAME.VEC;
@BOX 2.1
IN.STR (^F.NAME.VEC) => NUMBER;
DEFINE.INPUT (-1, PART (^F.NAME.VEC, 0, NUMBER - 1), %16, 0) => IN.CHANNEL;
SELECT.INPUT (IN.CHANNEL);
WHILE I.ENQ () & %8 = 0 DO
   OUT.BIN.B (IN.BIN.B ());
OD
SELECT.INPUT (0);
END.INPUT (IN.CHANNEL, 0);
OUT.CH ("$L");
@BOX 3.1
END
@END
/P/
@TITLE LIB13.1.6.2(1,10)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BEGIN
@BOX 2.0
ADD PREAMBLE TO HEADER ASSOCIATED
WITH OUTPUT STREAM TO DELIVERING
PROCESS. PUT DESTINATION INTO THE
HEADER. SEND THE MESSAGE TO THE
DELIVERING PROCESS.
SEND TO RECEIVER PROCESS.
@BOX 3.0
END
@BOX 1.1
BEGIN
INTEGER CHANNEL, TEMP.NUMBER, FILE.END;
LOGICAL8 [14] DESTINATION.PROCESS, TEMP.ARRAY;
DATAVEC DEST (LOGICAL8)
   "MAIL*/"
END
@BOX 2.1
FOR I < 6 DO
   DEST [I] => DESTINATION.PROCESS [I];
OD
IF MACHINE.ARRAY [INDEX * 9] /= 0 THEN
   FOR  I < MACHINE.ARRAY [INDEX * 9] DO
      MACHINE.ARRAY [INDEX * 9 + 1 + I] => DESTINATION.PROCESS [I + 6];
   OD
FI
0 => TEMP.ARRAY [2] => TEMP.ARRAY [3] => TEMP.ARRAY [4] => TEMP.ARRAY [5];
6 => TEMP.ARRAY [0];
FOR I < NAME.ARRAY [INDEX  * 9 => TEMP.NUMBER] DO
   NAME.ARRAY [TEMP.NUMBER + 1 + I] => TEMP.ARRAY [6 + I];
OD
I => TEMP.ARRAY [1];
SELECT.INPUT (OUTPUT.CHANNEL);
O.BPOS () => FILE.END;
SET.I.BPOS (0,0);
DEFINE.OUTPUT (-1, PART (^DESTINATION.PROCESS, 0, MACHINE.ARRAY [INDEX * 9] + 5)
, %36C00, 0, 0, 0) => CHANNEL;
SELECT.OUTPUT (CHANNEL);
OUT.HDR (PART (^TEMP.ARRAY, 0, TEMP.ARRAY [1] + 6));
FOR I < FILE.END DO
   OUT.BIN.B (IN.BIN.B ());
OD
END.OUTPUT (CHANNEL, 0);
SELECT.OUTPUT (0);
@BOX 3.1
END
@END
/P/
@TITLE LIB13.1.6.3(1,10)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
BEGIN
@BOX 2.0
FIND OUT IF USER WANTS
THE MESSAGE SAVED AND
ACT APPROPRIATELY
@BOX 3.0
END
@BOX 1.1
BEGIN
LOGICAL8 [20] FILE.NAME;
INTEGER SAVE.CHANNEL, END.FL, STR.SIZE;
@BOX 2.1
O.BPOS () => END.FL;
SELECT.OUTPUT (0);
CAPTION (%"DO YOU WANT IT SAVED ?");
NEW.LINES (1);
SELECT.INPUT (0);
WHILE IN.CH () => C.CHAR /= "Y" /= "N" DO
   CAPTION (%"ANSWER Y OR N");
   NEW.LINES (1);
   SKIP.LINE ();
OD
IF C.CHAR = "Y" THEN
   CAPTION (%"ENTER FILE NAME");
   IN.STR (^FILE.NAME) => STR.SIZE;
   DEFINE.OUTPUT (-1, PART (^FILE.NAME, 0, STR.SIZE-1), 0, 0, 0, 0) => SAVE.CHAN
NEL;
   SELECT.OUTPUT (SAVE.CHANNEL);
   SELECT.INPUT (OUTPUT.CHANNEL);
   SET.I.BPOS (0, 0);
   FOR I < END.FL  DO
      OUT.BIN.B (IN.BIN.B ());
   OD
   END.OUTPUT (SAVE.CHANNEL, 0);
   SELECT.OUTPUT (0);
FI
@BOX 3.1
END
@END
/P/
@TITLE LIB13.1.7(1,10)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
OUTPUT MESSAGE ID
@BOX 2.0
OUTPUT THE MESSAGE.ID TO BOTH THE TERMINAL AND
THE MESSAGE TO BE SENT.
@BOX 3.0
END
@BOX 1.1
BEGIN
INTEGER NBR, SPN;
LOGICAL64 JOB.NAME;

@BOX 2.1
DATAVEC MESSAGE.ID (LOGICAL8)
   "MESSAGE-ID: "
END
CAPTION (^MESSAGE.ID);
SELECT.OUTPUT (OUTPUT.CHANNEL);
CAPTION (^MESSAGE.ID);
NAMES ();
PWW3 => JOB.NAME;
LOOK.UP.PROCESS (JOB.NAME, 0);
PW1 => SPN;
OUT.I (SPN, 0);
OUT.HEX (TD, 8);
OUT.NAME (JOB.NAME);
NEW.LINES (1);
SELECT.OUTPUT (0);
OUT.I (SPN, 0);
OUT.HEX (TD, 8);
OUT.NAME (JOB.NAME);
NEW.LINES (1);
@BOX 3.1
END
@END
@TITLE LIB13.1.8(1,10)
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
OUTPUT TIME AND DATE
@BOX 2.0
OUTPUT THE TIME AND DATE TO BOTH
THE TERMINAL AND THE MESSAGE TO
BE SENT.
@BOX 3.0
END
@BOX 1.1
BEGIN
INTEGER I, END.POSITION;
@BOX 2.1
SELECT.OUTPUT (OUTPUT.CHANNEL);
DATAVEC DATE (LOGICAL8)
   "DATE: "
END
CAPTION (^DATE);
OUT.TD (TD, 1);
SPACES (10);
OUT.TD (TD, 0);
NEW.LINES (1);
SELECT.OUTPUT (0);
CAPTION (^DATE);
OUT.TD (TD, 1);
SPACES (10);
OUT.TD (TD, 0);
NEW.LINES (1);
@BOX 3.1
END
@END
@TITLE LIB13.2(1,10)
@COL 8N-7R-10N
@COL 1S-2R-3T-20N-5R-6F
@COL 9N-4R-21N
@ROW 8-3-9
@ROW 10-20-21
@FLOW 1-2-3NO-7-10-20-5-6
@FLOW 3YES-4-21-20
@BOX 1.0
DELETE MAIL
@BOX 2.0
SET UP I/O CHANNELS
READ THE TOTAL NUMBER OF MESSAGES
AND THE NUMBER ALREADY READ IN THE
POST FILE
@BOX 3.0
DOES THE USER NOT SPECIFY THE
MESSAGE TO DELETE ?
@BOX 4.0
UPDATE THE TOTAL NUMBER OF MESSAGES
AND THE NUMBER OF READ MESSAGES
DISPOSE OF ALL READ MESSAGES
@BOX 5.0
COPY REST OF THE POST FILE TO
THE UPDATED COPY
DISPOSE OF I/O STREAMS
@BOX 6.0
END
@BOX 7.0
UPDATE TOTAL NUMBER OF MESSAGES AND
NUMBER OF READ ONES
COPY MESSAGES TO UPDATED COPY OF MAIL
FILE UNTIL THE ONE TO BE DELETED IS FOUND
DELETE THAT MESSAGE
@BOX 1.1
PROC DELETE.MAIL (MESSAGE.ID);
LITERAL /ADDR [LOGICAL8] NULL =;
INTEGER OUT.CHAN, IN.CHAN, DISPOSAL.CHAN, TOTAL.MESSAGES,
   READ.ONES, I, CHAR.POS, LINE.POS;
@BOX 2.1
DEFINE.IO (-1, %"SCR*", %"POST.BOX", 0, 64, 0, 0) => OUT.CHAN;
DEFINE.INPUT (-1, %"POST.BOX", %18, 0) => IN.CHAN;
DEFINE.OUTPUT (-1, %"*", 0, 0, 0, 0) => DISPOSAL.CHAN;
SELECT.OUTPUT (OUT.CHAN);
SELECT.INPUT (IN.CHAN);
IN.I () => TOTAL.MESSAGES;
IN.I () => READ.ONES;
@BOX 3.1
IF SIZE (MESSAGE.ID) < 2
@BOX 4.1
OUT.I (TOTAL.MESSAGES - READ.ONES, 0);
OUT.CH ("$L");
OUT.I (0,0);
SELECT.OUTPUT (DISPOSAL.CHAN);
FOR I < READ.ONES DO
   WHILE NEXT.CH () /= "M" DO
      IN.BIN.B ();
   OD
   COPY.TO.START (NULL);
OD
SELECT.OUTPUT (OUT.CHAN);
IF READ.ONES /= 0  THEN
   FOR I < 3 DO
      OUT.CH ("$L");
   OD
FI
@BOX 5.1
WHILE I.ENQ () & 8 = 0 DO
   OUT.BIN.B (IN.BIN.B ());
OD
SELECT.OUTPUT (0);
SELECT.INPUT (0);
END.OUTPUT (OUT.CHAN, 0);
END.OUTPUT (DISPOSAL.CHAN, 0);
END.INPUT (IN.CHAN, 0);
@BOX 6.1
END
@BOX 7.1
OUT.I (TOTAL.MESSAGES - 1, 0);
OUT.CH ("$L");
OUT.I (READ.ONES - 1, 0);
COPY.TO.START (MESSAGE.ID);
WHILE NEXT.CH () = "$L" DO
   IN.BIN.B ();
OD
SELECT.OUTPUT (DISPOSAL.CHAN);
COPY.TO.START (NULL);
SELECT.OUTPUT (OUT.CHAN);
@END



@TITLE LIB13.3(1,10)
@COL 11R
@COL 1S-2R-3T-4T-5R-6R-7R-8F
@COL 10R
@ROW 11-4
@ROW 5-10
@FLOW 1-2-3NO-4NO-5-6-7-8
@FLOW 3YES-11-6
@FLOW 4YES-10-7
@BOX 1.0
READ MAIL
@BOX 2.0
SET UP INPUT/ OUTPUT FOR POST FILE
COPY THE NUMBER OF MESSAGES AND READ
THE NUMBER OF MESSAGES ALREADY READ
@BOX 3.0
DOES THE USER WANT ALL THE MESSAGES ?
@BOX 4.0
HAS THE USER SPECIFIED ANY MESSAGE.ID ?
@BOX 5.0
UPDATE THE NUMBER OF MESSAGES READ
READ TO START OF FIRST UNREAD MESSAGE
COPYING ALL CHARACTERS TO THE UPDATED
VERSION OF THE POST.FILE
@BOX 6.0
OUTPUT REQUIRED MESSAGE(S) TO TERMINAL
@BOX 7.0
FINISH COPYING MESSAGES TO NEW POST
FILE AND RELEASE INPUT AND OUTPUT
STREAMS
@BOX 8.0
END
@BOX 10.0
UPDATE THE NUMBER OF MESSAGES READ
COPY TO START OF REQUIRED MESSAGE
COPY REQUIRED MESSAGE TO TERMINAL
@BOX 11.0
UPDATE THE NUMBER OF MESSAGES READ
@BOX 1.1
PROC READ.MAIL (MESSAGE.ID);
LITERAL / ADDR [LOGICAL8] NULL =;
INTEGER OUT.CHAN, IN.CHAN, TOTAL.MESSAGES, READ.ONES,
   CHAR.POS, I, LINE.POS;
@BOX 2.1
DEFINE.IO (-1, %"SCR*", %"POST.BOX", 0, 64, 0, 0) => OUT.CHAN;
DEFINE.INPUT (-1, %"POST.BOX", %18, 0) => IN.CHAN;
SELECT.OUTPUT (OUT.CHAN);
SELECT.INPUT (IN.CHAN);
IN.I () => TOTAL.MESSAGES;
OUT.I (TOTAL.MESSAGES, 0);
OUT.CH ("$L");
IN.I () => READ.ONES;
@BOX 3.1
IF SIZE (MESSAGE.ID) = 1 AND MESSAGE.ID^ [0] = "A"
@BOX 4.1
IF SIZE (MESSAGE.ID) > 2
@BOX 5.1
OUT.I (TOTAL.MESSAGES,0);
FOR I < READ.ONES DO
   WHILE I.ENQ () & 8 = 0 AND NEXT.CH () /= "M" DO
      OUT.BIN.B (IN.BIN.B ());
   OD
   COPY.TO.START (NULL);
   WHILE I.ENQ () & 8 = 0 AND NEXT.CH () = "$L" DO
      OUT.BIN.B (IN.BIN.B ());
   OD
OD
I.BPOS () => CHAR.POS;
I.POS () => LINE.POS;
@BOX 6.1
SELECT.OUTPUT (0);
WHILE I.ENQ () & 8 = 0 DO
   OUT.BIN.B (IN.BIN.B ());
OD
SELECT.OUTPUT (OUT.CHAN);
@BOX 7.1
BREAK.OUTPUT (0);
SET.I.BPOS (CHAR.POS, LINE.POS);
WHILE I.ENQ () & 8 = 0 DO
   OUT.BIN.B (IN.BIN.B ());
OD
END.OUTPUT (OUT.CHAN, 0);
END.INPUT (IN.CHAN, 0);
SELECT.INPUT (0);
SELECT.OUTPUT (0);
@BOX 8.1
END
@BOX 10.1
OUT.I (READ.ONES, 0);
COPY.TO.START (MESSAGE.ID);
I.BPOS ()=> CHAR.POS;
I.POS () => LINE.POS;
SELECT.OUTPUT (0);
WHILE NEXT.CH () = "$L" DO
   OUT.BIN.B (IN.BIN.B ());
OD
COPY.TO.START (NULL);
SELECT.OUTPUT (OUT.CHAN);
OUT.CH ("$L");
@BOX 11.1
OUT.I (TOTAL.MESSAGES, 0);
I.BPOS () => CHAR.POS;
I.POS () => LINE.POS;
@END
@TITLE LIB13.4(1,10)
@COL 1S-2R-14N-3R-4T-5R-6T-7T-8R-9T-10R-11F
@COL 13N-12R
@ROW 14-13
@ROW 10-12
@FLOW 1-2-14-3-4NO-5-6NO-7-8-9NO-10-11
@FLOW 4YES-11
@FLOW 6YES-13-14
@FLOW 7YES-10
@FLOW 9YES-12-13-14
@BOX 1.0
COPY TO START
@BOX 2.0
SET TO NO ADDITIONAL SPACES
REQUIRED BETWEEN MESSAGES
@BOX 3.0
COPY FROM INPUT STREAM TO OUTPUT
STREAM UNTIL A LINE FEED IS FOUND
THEN COUNT THE LINE FEEDS
@BOX 4.0
HAS THE END OF FILE BEEN REACHED ?
@BOX 5.0
IF THERE WERE MULTIPLE LINE FEEDS
CHECK IF THEY ARE FOLLOWED BY A
NEW MESSAGE
@BOX 6.0
WAS IT NOT THE START OF A NEW MESSAGE ?
@BOX 7.0
WAS NO MESSAGE ID SPECIFIED ?
@BOX 8.0
CHECK IF THE MESSAGE ID MATCHES
@BOX 9.0
DOES IT NOT MATCH ?
@BOX 10.0
FINISH OUTPUT OF LAST READ CHARACTER
SET INPUT AND OUTPUT POINTERS BACK
TO THE START OF THE MESSAGE
@BOX 11.0
END
@BOX 12.0
OUTPUT THE LAST CHARACTER
READ
@BOX 1.1
PROC COPY.TO.START (MESSAGE.ID);
DATAVEC START.OF.MESSAGE (LOGICAL8)
   "MESSAGE-ID: "
END
INTEGER I.CHAN, I, STORED.SIZE;
LOGICAL8 SPACES.WANTED, LAST.CHAR;
@BOX 2.1
"N" => SPACES.WANTED;
1 => I;
@BOX 3.1
WHILE I.ENQ () & 8 = 0 AND IN.CH () => LAST.CHAR /= "$L" DO
   OUT.CH (LAST.CHAR);
OD
1 => I;
OUT.CH (LAST.CHAR);
WHILE I.ENQ () & 8 = 0 AND IN.CH () => LAST.CHAR = "$L" DO
   OUT.CH (LAST.CHAR);
   1 +> I;
OD
@BOX 4.1
IF I.ENQ () & 8 /= 0
@BOX 5.1
IF I > 1 THEN
   IF NEXT.CH () = 0 THEN
      WHILE I.ENQ () & 8 = 0 AND [NEXT.CH ()= 0 OR NEXT.CH () = "$L"] DO
         IN.CH ();
      OD
      IF I.ENQ () & 8 = 0 THEN
         IN.CH () => LAST.CHAR;
      FI
   FI
   0 => I;
   "N" => SPACES.WANTED;
   WHILE LAST.CHAR = START.OF.MESSAGE [I] DO
      OUT.CH (LAST.CHAR);
      IN.CH () => LAST.CHAR;
      1 +> I;
   OD
ELSE
   OUT.CH (LAST.CHAR);
FI

@BOX 6.1
IF I /= 12
@BOX 7.1
0 => I;
IF SIZE (MESSAGE.ID) => STORED.SIZE < 1
@BOX 8.1
"Y" => SPACES.WANTED;
WHILE I < STORED.SIZE AND LAST.CHAR = MESSAGE.ID^ [I] DO
   OUT.CH (LAST.CHAR);
   IN.CH () => LAST.CHAR;
   1 +> I;
OD
@BOX 9.1
IF I /= STORED.SIZE
@BOX 10.1
IF I = 0 THEN
   OUT.CH (LAST.CHAR);
FI
SET.I.BPOS (I.BPOS () - I - 14, I.POS ());
SET.O.BPOS (O.BPOS () - I - 14, O.POS ());
@BOX 11.1
END
@BOX 12.1
OUT.CH (LAST.CHAR);
@END
