<> <> <> DIRECTORY IO, Process, Protocols, RefText, Rope; EchoProtocol: CEDAR PROGRAM IMPORTS IO, Process, Protocols, RefText = {OPEN Protocols; echo: Protocol _ NEW [ProtocolRep _ [ name: "Echo", Instantiate: Instantiate, StartConnect: StartConnect, StartDisconnect: StartDisconnect, GiveUp: GiveUp, SetOnLine: SetOnLine, protocolData: NIL]]; Instantiate: PROC [client: Client, logFileName: ROPE _ NIL] RETURNS [c: Conversant] ~ { c _ NEW [ConversantPrivate _ [echo, client, [FALSE, disconnected], NIL, client.fromClient, NIL]]; TRUSTED {Process.Detach[FORK Copy[from: client.fromClient, to: client.toClient]]}; RETURN}; StartConnect: PROC [c: Conversant, serverName: ROPE, login: BOOL _ FALSE] ~ { c.state.onLine _ TRUE; c.state.connectivity _ connected; c.client.type.NoteState[c]; RETURN}; StartDisconnect: PROC [c: Conversant, verbosely: BOOL _ TRUE] = { c.state.onLine _ FALSE; c.state.connectivity _ disconnected; c.client.type.NoteState[c]; RETURN}; SetOnLine: PROC [c: Conversant, onLine: BOOL] ~ { c.state.onLine _ onLine; c.client.type.NoteState[c]; RETURN}; GiveUp: PROC [c: Conversant, verbosely: BOOL _ TRUE] ~ {RETURN}; Copy: PROC [from, to: IO.STREAM] ~ { bufsize: NAT ~ bufferSize; buff: REF TEXT ~ RefText.New[bufsize]; {ENABLE IO.Error, IO.EndOfStream => CONTINUE; WHILE NOT from.EndOf[] DO ask: NAT ~ MIN[from.CharsAvail[TRUE], bufsize]; got: NAT _ from.GetBlock[buff, 0, ask !IO.EndOfStream => EXIT]; IF got=0 THEN ERROR--yet another bloody fool hasn't implemented an IO class correctly--; to.PutBlock[buff]; ENDLOOP; }; from.Close[!IO.Error => CONTINUE]; to.Close[!IO.Error => CONTINUE]; RETURN}; bufferSize: NAT _ 1024; Protocols.RegProtocol[echo]; }.