-- Transport mechanism: Maintain:  raw communications

-- [Juniper]<Grapevine>Maintain>MaintainComm.mesa

-- Andrew Birrell  14-Jan-82  9:37:23

DIRECTORY
BodyDefs	USING[ Connect, oldestTime, Password, Remark, RName ],
LocateDefs	USING[ FindRegServer, FoundServerInfo ],
MaintainPrivate	USING[ Failed, Handle, TypeRC ],
ProtocolDefs,
PupDefs		USING[ AppendPupAddress, PupAddress ];

MaintainComm: PROGRAM
IMPORTS LocateDefs, MaintainPrivate, ProtocolDefs, PupDefs
EXPORTS MaintainPrivate =

BEGIN

OPEN MaintainPrivate;

-- Actual communication with the registration servers --

Update: PUBLIC PROC[handle: MaintainPrivate.Handle,
                    op: ProtocolDefs.RSOperation, name: BodyDefs.RName,
                    value: BodyDefs.RName ← NIL,
                    connect: BodyDefs.Connect ← NIL,
                    remark: BodyDefs.Remark ← NIL,
                    key: BodyDefs.Password ← [0,0,0,0],
                    sendRList: PROC[ProtocolDefs.Handle] ← NIL ] =
   BEGIN
   rc: ProtocolDefs.ReturnCode =
               Operate[handle, op, name, value, connect, remark, key];
   END;


Operate: PUBLIC PROC[handle: MaintainPrivate.Handle,
                    op: ProtocolDefs.RSOperation, name: BodyDefs.RName,
                    value: BodyDefs.RName ← NIL,
                    connect: BodyDefs.Connect ← NIL,
                    remark: BodyDefs.Remark ← NIL,
                    key: BodyDefs.Password ← [0,0,0,0],
                    sendRList: PROC[ProtocolDefs.Handle] ← NIL ]
        RETURNS[ rc: ProtocolDefs.ReturnCode ] =
   BEGIN
   OPEN ProtocolDefs;
   TryUpdate: PROC[str: ProtocolDefs.Handle] =
      BEGIN
      SendRSOperation[str, op];
      IF op # NoOp THEN SendRName[str, name];
      SELECT op FROM
        IN [Expand..ReadEntry] =>
          SendTimestamp[str, BodyDefs.oldestTime];
        IdentifyCaller =>
          SendPassword[str:str, pw: key, key: [0,0,0,0]];
        IN [AddMember..DeleteFriend], NewName,
        IN [IsMemberDirect..IsFriendClosure] =>
          { IF value = NIL THEN ERROR; SendRName[str, value] };
        Authenticate, CreateIndividual, ChangePassword =>
          SendPassword[str:str, pw: key, key: handle.callerKey];
        ChangeConnect =>
          { IF connect = NIL THEN ERROR; SendConnect[str, connect] };
        ChangeRemark =>
          { IF remark = NIL THEN ERROR; SendRemark[str, remark] };
        AddListOfMembers =>
          { IF sendRList = NIL THEN ERROR; sendRList[str] };
      ENDCASE => NULL;
      SendNow[str];
      IF op # NoOp THEN rc ← ReceiveRC[str];
      END;
   oldBad: BOOLEAN ← FALSE;
   Create: PROC =
      BEGIN
      serverSite: STRING = [21] --377#377#177777|177777--;
      PupDefs.AppendPupAddress[serverSite, handle.serverAddr];
      handle.glass.WriteString[serverSite];
      handle.glass.WriteString[" ... "L];
      handle.glass.SendNow[];
      handle.str ← ProtocolDefs.CreateStream[handle.serverAddr];
      IF handle.authenticated
      THEN BEGIN
           SendRSOperation[handle.str, IdentifyCaller];
           ProtocolDefs.SendRName[handle.str, handle.caller];
           ProtocolDefs.SendPassword[str:handle.str,
                                     pw: handle.callerKey,
                                     key:[0,0,0,0]];
           ProtocolDefs.SendNow[handle.str];
           rc ← ReceiveRC[handle.str];
           IF rc.code # done
           THEN BEGIN
                handle.authenticated ← FALSE;
                handle.glass.WriteString[
                       "your name/password is not valid! ... "L];
                END; 
           END;
      END;
   Destroy: PROC =
      BEGIN
      IF handle.str # NIL THEN DestroyStream[handle.str];
      handle.str ← NIL;
      END;
   Accept: PROC[addr: PupDefs.PupAddress]RETURNS[BOOLEAN] =
      BEGIN
      addr.socket ← RegServerEnquirySocket;
      IF handle.str # NIL AND handle.serverAddr # addr THEN Destroy[];
      IF handle.str = NIL
      THEN BEGIN
           handle.serverAddr ← addr;
           Create[ ! Failed => GOTO failed];
           handle.addrKnown ← TRUE;
           END;
      RETURN[TRUE];
      EXITS failed => RETURN[FALSE]
      END;
   handle.glass.WriteString[" ... "L]; handle.glass.SendNow[];
   SELECT op FROM
     NoOp, CheckStamp, Authenticate, IdentifyCaller =>
       NULL;
   ENDCASE =>
     IF NOT handle.authenticated
     THEN { handle.glass.WriteString["please login first"L];
            ERROR MaintainPrivate.Failed[] }; 
   BEGIN
      IF handle.str # NIL
      THEN BEGIN
           TryUpdate[ handle.str ! Failed => GOTO streamGone ];
           EXITS streamGone => Destroy[];
           END;
      IF handle.str = NIL
      THEN BEGIN
           IF handle.addrKnown
           THEN Create[ ! Failed => GOTO notThere]
           ELSE BEGIN
                [] ← LocateDefs.FindRegServer["x.GV"L, Accept];
                IF handle.str = NIL THEN GOTO notThere;
                END;
           TryUpdate[handle.str ! Failed => GOTO notThere];
           END;
      IF rc.code = WrongServer
      THEN oldBad ← TRUE
      ELSE oldBad ← FALSE;
   EXITS notThere => { Destroy[]; oldBad ← TRUE };
   END;
   IF oldBad
   THEN BEGIN -- need to find the correct R-Server --
        foundInfo: LocateDefs.FoundServerInfo;
        handle.glass.WriteString["Locating registration server ... "L];
        foundInfo ← LocateDefs.FindRegServer[name, Accept];
        WITH foundInfo SELECT FROM
          notFound => rc ← [BadRName, notFound];
          allDown => rc ← [AllDown, notFound];
          found =>
            BEGIN
            TryUpdate[ handle.str ! Failed => GOTO down ];
            EXITS down =>
              { Destroy[]; rc ← [AllDown, notFound] };
            END;
        ENDCASE => ERROR;
        END;
   IF rc.code = done
   THEN handle.glass.WriteString["done"L]
   ELSE MaintainPrivate.TypeRC[handle, op, rc, name, value];
   END;

END.