-- Transport Mechanism: Maintain: Type Entry

-- [Juniper]<Grapevine>maintain>MaintainType.mesa

-- Andrew Birrell  14-Jan-82 13:08:17
-- Philip Karlton  15-May-81 16:51:40

DIRECTORY
Ascii		USING[ CR, SP ],
BodyDefs	USING[ Connect, maxConnectLength, maxRemarkLength,
		       maxRNameLength, Password, Remark, RName, RNameSize,
		       Timestamp ],
GlassDefs	USING[ Handle ],
MaintainPrivate	USING[ CopyName, Del, Handle, Operate, ReadWord, TypeType ],
ProtocolDefs,
Stream,
String		USING[ AppendNumber ],
Time		USING[ Append, Unpack ];

MaintainType: PROGRAM
IMPORTS BodyDefs, MaintainPrivate, ProtocolDefs, Stream, String, Time
EXPORTS MaintainPrivate =

BEGIN

OPEN MaintainPrivate;

TypeEntry: PUBLIC PROCEDURE[handle: MaintainPrivate.Handle] =
   { DisplayEntry[handle, brief] };

TypeMembers: PUBLIC PROCEDURE[handle: MaintainPrivate.Handle] =
   BEGIN
   OPEN handle;
   rc: ProtocolDefs.ReturnCode;
   ReadWord[glass, " of group: "L, dName];
   rc ← Operate[handle: handle, op: ReadMembers, name: dName];
   IF rc.code = done
   THEN BEGIN
        [] ← ProtocolDefs.ReceiveTimestamp[str];
        CopyName[from: dName, to: group];
        TypeRList[glass, str, "Members:"L, contents];
        END;
   END;

TypeDetails: PUBLIC PROCEDURE[handle: MaintainPrivate.Handle] =
   { DisplayEntry[handle, full] };     


Detail: TYPE = {brief, full};

DisplayEntry: PROC[handle: MaintainPrivate.Handle, amount: Detail ] =
   BEGIN
   OPEN handle;
   rc: ProtocolDefs.ReturnCode;
   items: CARDINAL;
   ReadWord[glass, " for R-Name: "L, dName];
   rc ← Operate[handle: handle, op: ReadEntry, name: dName];
   IF rc.code = done THEN [] ← ProtocolDefs.ReceiveTimestamp[str];
   items ← IF rc.code = done
           THEN ProtocolDefs.ReceiveCount[str]
           ELSE 0;
   IF rc.code = done THEN TypeType[glass, rc.type];
   SELECT rc.type FROM
     notFound => NULL;
     dead => TypePrefix[glass, str, amount];
     individual =>
       BEGIN
       CopyName[from: dName, to: individual];
       TypePrefix[glass, str, amount];
       TypePassword[glass, str, amount];
       TypeConnect[glass, str, amount];
       TypeRList[glass, str,"Forwarding:"L, contents];
       TypeStampList[glass, str, amount];
       TypeRList[glass, str, "DelForwarding:"L,
                 IF amount=full THEN contents ELSE none];
       TypeStampList[glass, str, amount];
       TypeRList[glass, str, "Mailbox-sites:"L, contents];
       TypeStampList[glass, str, amount];
       TypeRList[glass, str, "DelMailboxSites:"L,
                 IF amount=full THEN contents ELSE none];
       TypeStampList[glass, str, amount];
       END;
     group =>
       BEGIN
       CopyName[from: dName, to: group];
       TypePrefix[glass, str, amount ];
       TypeRemark[glass, str, amount];
       TypeRList[glass, str, "Members:"L,
                 IF amount=brief THEN total ELSE contents];
       TypeStampList[glass, str, amount];
       TypeRList[glass, str, "DelMembers:"L,
                 IF amount=full THEN contents ELSE none];
       TypeStampList[glass, str, amount];
       TypeRList[glass, str, "Owners:"L, contents];
       TypeStampList[glass, str, amount];
       TypeRList[glass, str, "DelOwners:"L,
                 IF amount=full THEN contents ELSE none];
       TypeStampList[glass, str, amount];
       TypeRList[glass, str, "Friends:"L, contents];
       TypeStampList[glass, str, amount];
       TypeRList[glass, str, "DelFriends:"L,
                 IF amount=full THEN contents ELSE none];
       TypeStampList[glass, str, amount];
       END;
     ENDCASE => ERROR;
   END;

TypePrefix: PROC[glass: GlassDefs.Handle,
                 str: ProtocolDefs.Handle, amount: Detail] =
   BEGIN
   -- type it iff amount = full
   OPEN glass;
   length: CARDINAL = ProtocolDefs.ReceiveCount[str];
   type: ProtocolDefs.RNameType;
   name: BodyDefs.RName = [BodyDefs.maxRNameLength];
   IF amount = full
   THEN { WriteChar[Ascii.CR]; WriteString["Prefix: "L]; };
   TypeTimestamp[glass, str, amount];
   type ← LOOPHOLE[ProtocolDefs.ReceiveCount[str]];
   IF amount = full THEN TypeType[glass, type];
   IF amount = full THEN WriteString[", "L];
   [] ← TypeRName[glass, str, amount];
   END;

TypeRList: PROC[glass: GlassDefs.Handle, str: ProtocolDefs.Handle,
                text: STRING, amount: {contents, total, none}] =
   BEGIN
   OPEN glass;
   length: CARDINAL ← ProtocolDefs.ReceiveCount[str];
   IF amount # none
   THEN{ WriteChar[Ascii.CR]; WriteString[text]; WriteChar[Ascii.SP] };
   IF length = 0 
   THEN { IF amount # none THEN WriteString["none"L] }
   ELSE BEGIN
        count: CARDINAL ← 0;
        DO length ← length - TypeRName[glass, str,
                                IF amount=contents THEN full ELSE brief];
           count ← count+1;
           IF length = 0 THEN EXIT;
           IF amount = contents THEN WriteString[", "L];
        ENDLOOP;
        IF amount=total THEN WriteDecimal[count];
        END;
   END;

TypeStampList: PROC[glass: GlassDefs.Handle,
                    str: ProtocolDefs.Handle, amount: Detail] =
   BEGIN
   -- type it iff amount = full
   OPEN glass;
   length: CARDINAL ← ProtocolDefs.ReceiveCount[str];
   IF amount = full
   THEN { WriteChar[Ascii.CR]; WriteString["Stamp-list: "] };
   IF length = 0 
   THEN { IF amount = full THEN WriteString ["null"L] }
   ELSE DO TypeTimestamp[glass, str, amount];
           length ← length - SIZE[BodyDefs.Timestamp];
           IF length = 0 THEN EXIT;
           IF amount = full THEN WriteString[", "L];
        ENDLOOP;
   END;

TypeRName: PROC[glass: GlassDefs.Handle,
                str: ProtocolDefs.Handle, amount: Detail]
        RETURNS[length: CARDINAL] =
   BEGIN
   -- type it iff amount = full
   OPEN glass;
   rName: BodyDefs.RName = [BodyDefs.maxRNameLength];
   ProtocolDefs.ReceiveRName[str, rName];
   IF DelTyped[] THEN ERROR MaintainPrivate.Del[];
   IF amount = full
   THEN WriteString[rName];
   RETURN[BodyDefs.RNameSize[rName]]
   END;

TypeTimestamp: PROC[glass: GlassDefs.Handle,
                    str: ProtocolDefs.Handle, amount: Detail] =
   BEGIN
   -- type it iff amount = full
   OPEN glass;
   WriteOctal: PROC[n: CARDINAL] =
      BEGIN
      buffer: STRING = [6] --177777--;
      String.AppendNumber[buffer, n, 8];
      WriteString[buffer];
      END;
   stamp: BodyDefs.Timestamp;
   text: STRING = [50];
   stamp ← ProtocolDefs.ReceiveTimestamp[str];
   IF DelTyped[] THEN ERROR MaintainPrivate.Del[];
   IF amount = full
   THEN BEGIN
        WriteChar['[];
        WriteOctal[stamp.net];
        WriteChar['#];
        WriteOctal[stamp.host];
        WriteChar[',];
        Time.Append [text, Time.Unpack [LOOPHOLE[stamp.time]]];
        WriteString[text];
        WriteChar[']];
        END;
   END;

TypePassword: PROC[glass: GlassDefs.Handle,
                   str: ProtocolDefs.Handle, amount: Detail] =
   BEGIN
   -- type it iff amount = full
   OPEN glass;
   length: CARDINAL = ProtocolDefs.ReceiveCount[str];
   IF amount = full
   THEN { WriteChar[Ascii.CR]; WriteString["Password: "L]; };
   IF amount = full THEN WriteString["(stamp="L];
   TypeTimestamp[glass, str, amount];
   IF amount = full THEN WriteString[") "L];
   BEGIN
      pw: BodyDefs.Password = ProtocolDefs.ReceivePassword[str, [0,0,0,0]];
      IF amount = full
      THEN FOR i: CARDINAL IN [0 .. LENGTH[pw])
           DO WriteDecimal[pw[i]]; WriteChar[Ascii.SP] ENDLOOP;
   END;
   END;

TypeConnect: PROC[glass: GlassDefs.Handle,
                  str: ProtocolDefs.Handle, amount: Detail] =
   BEGIN
   -- type it always
   OPEN glass;
   length: CARDINAL = ProtocolDefs.ReceiveCount[str]
                        - SIZE[BodyDefs.Timestamp];
   WriteChar[Ascii.CR]; WriteString["Connect-site: "L];
   IF amount = full THEN WriteString["(stamp="L];
   TypeTimestamp[glass, str, amount];
   IF amount = full THEN WriteString[") "L];
   IF length = 0
   THEN WriteString[ "null"L]
   ELSE BEGIN
        connect: BodyDefs.Connect = [BodyDefs.maxConnectLength];
        connect.length ← ProtocolDefs.ReceiveCount[str];
        GetBlock[ str, [@(connect.text), (1+connect.length)/2] ];
        WriteString[connect];
        END;
   END;

TypeRemark: PROC[glass: GlassDefs.Handle,
                 str: ProtocolDefs.Handle, amount: Detail] =
   BEGIN
   -- type it always
   OPEN glass;
   length: CARDINAL = ProtocolDefs.ReceiveCount[str]
                        - SIZE[BodyDefs.Timestamp];
   WriteChar[Ascii.CR]; WriteString["Remark: "L];
   IF amount = full THEN WriteString["(stamp="L];
   TypeTimestamp[glass, str, amount];
   IF amount = full THEN WriteString[") "L];
   IF length = 0
   THEN WriteString[ "null"L]
   ELSE BEGIN
        remark: BodyDefs.Remark = [BodyDefs.maxRemarkLength];
        remark.length ← ProtocolDefs.ReceiveCount[str];
        GetBlock[ str, [@(remark.text), (1+remark.length)/2] ];
        WriteString[remark];
        END;
   END;

GetBlock: PROC[str: ProtocolDefs.Handle,
               block: RECORD[where: POINTER, length: CARDINAL]] =
   BEGIN
   used: CARDINAL;
   why: Stream.CompletionCode;
   sst: Stream.SubSequenceType;
   [used, why, sst] ← Stream.GetBlock[str,[block.where, 0, 2*block.length]];
   IF used # 2*block.length OR why = sstChange
   THEN ERROR ProtocolDefs.Failed[protocolError];
   END;

END.