GVProtocolImpl.mesa - subroutines for mail and reg server protocols
Copyright © 1985 by Xerox Corporation. All rights reserved.
Hal Murray May 27, 1985 9:12:23 pm PDT
Russ Atkinson (RRA) October 18, 1985 1:18:30 pm PDT
Hal Murray, May 12, 1986 10:02:01 pm PDT
DIRECTORY
Basics USING [BITSHIFT, BITXOR, bytesPerWord],
ConvertUnsafe USING [ToRope],
Endian USING [HWORD],
GVBasics USING [Connect, GVString, ItemHeader, maxGVStringLength, oldestTime, Password, Remark, RName, Timestamp],
GVNames USING [RSOperation],
GVProtocol USING [FailureReason, GVSocket, Handle, MSOperation, ReturnCode],
IO USING [Close, EndOfStream, Flush, GetChar, PutChar, PutFR, PutRope, STREAM, UnsafeBlock, UnsafeGetBlock, UnsafePutBlock],
IOExtras USING [GetHWord, PutHWord],
Pup USING [Address, nullSocket, Socket],
PupSocket USING [IsThisMe],
PupStream USING [Create, StreamClosing, Timeout],
PupWKS USING [gvLily, gvMSClientInput, gvMSForward, gvMSPoll, gvMSRetrieve, gvRSPoll, gvRSEnquiry],
Rope USING [Fetch, Length, ROPE];
GVProtocolImpl: CEDAR MONITOR
IMPORTS Basics, ConvertUnsafe, IO, IOExtras, PupSocket, PupStream, Rope
EXPORTS GVBasics, GVProtocol = {
Handle: TYPE = GVProtocol.Handle;
MakeKey: PUBLIC PROC [password: Rope.ROPE] RETURNS [key: GVBasics.Password] = {
key ← ALL[0];
FOR i: CARDINAL IN CARDINAL[0..Rope.Length[password]) DO
j: [0..LENGTH[key]) = (i/bpw) MOD LENGTH[key];
c: WORD = LOOPHOLE[ IF Rope.Fetch[password, i] IN ['A..'Z]
THEN Rope.Fetch[password, i] - 'A + 'a
ELSE Rope.Fetch[password, i] ];
key[j] ← Basics.BITXOR[key[j], Basics.BITSHIFT[c, IF (i MOD 2) = 0 THEN 9 ELSE 1]];
ENDLOOP;
};
RopeFromTimestamp: PUBLIC PROC [stamp: GVBasics.Timestamp] RETURNS [r: Rope.ROPE] = {
r ← IO.PutFR["%b#%b@%g", [integer[stamp.net]], [integer[stamp.host]], [cardinal[stamp.time]]];
};
bpw: INT = Basics.bytesPerWord;
SocketsArray: TYPE = ARRAY GVProtocol.GVSocket OF Pup.Socket;
sockets: REF SocketsArray ← NEW[SocketsArray ← [
none: Pup.nullSocket,
RSEnquiry: PupWKS.gvRSEnquiry,
RSPoll: PupWKS.gvRSPoll,
Lily: PupWKS.gvLily,
MSPoll: PupWKS.gvMSPoll,
MSForward: PupWKS.gvMSForward,
MSSend: PupWKS.gvMSClientInput,
MSRetrieve: PupWKS.gvMSRetrieve
]];
SetTestingMode: PUBLIC ENTRY PROC = {
FOR s: GVProtocol.GVSocket IN GVProtocol.GVSocket DO sockets[s].b ← 1 ENDLOOP;
};
GetSocket: PUBLIC ENTRY PROC [gv: GVProtocol.GVSocket] RETURNS [Pup.Socket] = {
RETURN[sockets[gv]];
};
IsLocal: PUBLIC PROC [addr: Pup.Address] RETURNS [BOOL] = {
RETURN[PupSocket.IsThisMe[addr]];
};
Failed: PUBLIC SIGNAL [why: GVProtocol.FailureReason, text: Rope.ROPE] = CODE;
CreateStream: PUBLIC PROC [host: Pup.Address, socket: GVProtocol.GVSocket, secs: INT ← 120] RETURNS [Handle] = {
ENABLE PupStream.StreamClosing => ERROR Failed[communicationError, text];
IF socket # none THEN host.socket ← sockets[socket];
RETURN[PupStream.Create[host, secs*1000, secs*1000]];
};
SendNow: PUBLIC PROC [str: Handle] = {
ENABLE {
PupStream.StreamClosing => ERROR Failed[communicationError, text];
PupStream.Timeout => SIGNAL Failed[noData, "Server not reading data"]; };
IO.Flush[str];
};
Close: PUBLIC PROC [str: Handle] = {
IO.Close[str];
};
Byte: TYPE = [0..256);
SendAck: PUBLIC PROC [str: Handle] = {
SendByte[str, 0];
};
ReceiveAck: PUBLIC PROC [str: Handle] = {
[] ← ReceiveByte[str];
};
SendBoolean: PUBLIC PROC [str: Handle, bool: BOOL] = {
SendByte[str, IF bool THEN 1 ELSE 0];
};
ReceiveBoolean: PUBLIC PROC [str: Handle] RETURNS [BOOL] = {
RETURN[ReceiveByte[str] # 0];
};
SendByte: PUBLIC PROC [str: Handle, byte: Byte] = {
ENABLE {
PupStream.StreamClosing => ERROR Failed[communicationError, text];
PupStream.Timeout => SIGNAL Failed[noData, "Server not reading data"]; };
IO.PutChar[str, LOOPHOLE[byte]];
};
ReceiveByte: PUBLIC PROC [str: Handle] RETURNS [byte: Byte] = {
ENABLE {
PupStream.StreamClosing => ERROR Failed[communicationError, text];
PupStream.Timeout => SIGNAL Failed[noData, "Server not sending data"];
IO.EndOfStream => ERROR Failed[protocolError, "Unexpected \"mark\""]; };
byte ← LOOPHOLE[IO.GetChar[str]];
};
SendCount: PUBLIC PROC [str: Handle, count: Endian.HWORD] = TRUSTED {
ENABLE {
PupStream.StreamClosing => ERROR Failed[communicationError, text];
PupStream.Timeout => SIGNAL Failed[noData, "Server not reading data"]; };
IOExtras.PutHWord[str, count];
};
ReceiveCount: PUBLIC PROC [str: Handle] RETURNS [count: Endian.HWORD] = TRUSTED {
ENABLE {
PupStream.StreamClosing => ERROR Failed[communicationError, text];
PupStream.Timeout => SIGNAL Failed[noData, "Server not sending data"];
IO.EndOfStream => ERROR Failed[protocolError, "Unexpected \"mark\""]; };
count ← IOExtras.GetHWord[str];
};
SendItemHeader: PUBLIC PROC [str: Handle, header: GVBasics.ItemHeader] = TRUSTED {
SendBytes[str, [LOOPHOLE[LONG[@header]], 0, bpw*SIZE[GVBasics.ItemHeader]]];
};
ReceiveItemHeader: PUBLIC PROC [str: Handle] RETURNS [header: GVBasics.ItemHeader] = TRUSTED {
ReceiveBytes[str, [LOOPHOLE[LONG[@header]], 0, bpw*SIZE[GVBasics.ItemHeader]]];
};
SendTimestamp: PUBLIC PROC [str: Handle, stamp: GVBasics.Timestamp] = TRUSTED {
SendBytes[str, [LOOPHOLE[LONG[@stamp]], 0, bpw*SIZE[GVBasics.Timestamp]]];
};
ReceiveTimestamp: PUBLIC PROC [str: Handle] RETURNS [stamp: GVBasics.Timestamp] = TRUSTED {
ReceiveBytes[str, [LOOPHOLE[LONG[@stamp]], 0, bpw*SIZE[GVBasics.Timestamp]]];
};
SendPassword: PUBLIC PROC [str: Handle, pw: GVBasics.Password] = TRUSTED {
SendBytes[str, [LOOPHOLE[LONG[@pw]], 0, bpw*SIZE[GVBasics.Password]]];
};
ReceivePassword: PUBLIC PROC [str: Handle] RETURNS [pw: GVBasics.Password] = TRUSTED {
ReceiveBytes[str, [LOOPHOLE[LONG[@pw]], 0, bpw*SIZE[GVBasics.Password]]];
};
SendRC: PUBLIC PROC [str: Handle, rc: GVProtocol.ReturnCode] = TRUSTED {
SendBytes[str, [LOOPHOLE[LONG[@rc]], 0, bpw*SIZE[GVProtocol.ReturnCode]]];
};
ReceiveRC: PUBLIC PROC [str: Handle] RETURNS [rc: GVProtocol.ReturnCode] = TRUSTED {
ReceiveBytes[str, [LOOPHOLE[LONG[@rc]], 0, bpw*SIZE[GVProtocol.ReturnCode]]];
};
SendMSOperation: PUBLIC PROC [str: Handle, op: GVProtocol.MSOperation] = TRUSTED {
SendBytes[str, [LOOPHOLE[LONG[@op]], 0, bpw*SIZE[GVProtocol.MSOperation]]];
};
ReceiveMSOperation: PUBLIC PROC [str: Handle] RETURNS [op: GVProtocol.MSOperation] = TRUSTED {
ReceiveBytes[str, [LOOPHOLE[LONG[@op]], 0, bpw*SIZE[GVProtocol.MSOperation]]];
};
SendRSOperation: PUBLIC PROC [str: Handle, op: GVNames.RSOperation] = TRUSTED {
SendBytes[str, [LOOPHOLE[LONG[@op]], 0, bpw*SIZE[GVNames.RSOperation]]];
};
ReceiveRSOperation: PUBLIC PROC [str: Handle] RETURNS [op: GVNames.RSOperation] = TRUSTED {
ReceiveBytes[str, [LOOPHOLE[LONG[@op]], 0, bpw*SIZE[GVNames.RSOperation]]];
};
SendBytes: PUBLIC PROC [str: Handle, block: IO.UnsafeBlock] = {
ENABLE {
PupStream.StreamClosing => ERROR Failed[communicationError, text];
PupStream.Timeout => SIGNAL Failed[noData, "Server not reading data"]; };
IO.UnsafePutBlock[str, block];
};
ReceiveBytes: PUBLIC UNSAFE PROC [str: Handle, block: IO.UnsafeBlock] = TRUSTED {
ENABLE {
PupStream.StreamClosing => ERROR Failed[communicationError, text];
PupStream.Timeout => SIGNAL Failed[noData, "Server not sending data"];
IO.EndOfStream => ERROR Failed[protocolError, "Protocol error: unexpected \"mark\""]; };
nBytes: INT = IO.UnsafeGetBlock[str, block];
IF nBytes # block.count THEN
ERROR Failed[protocolError, "Protocol error: unexpected \"mark\""];
};
StringSize: PUBLIC PROC [string: GVBasics.GVString] RETURNS [INT] = {
RETURN[2 + (Rope.Length[string] + bpw-1) / bpw];
};
SendRName: PUBLIC PROC [str: Handle, name: GVBasics.RName] = {
SendGVString[str, name];
};
ReceiveRName: PUBLIC PROC [str: Handle] RETURNS [GVBasics.RName] = {
RETURN[ReceiveGVString[str]];
};
SendConnect: PUBLIC PROC [str: Handle, connect: GVBasics.Connect] = {
SendGVString[str, connect];
};
ReceiveConnect: PUBLIC PROC [str: Handle] RETURNS [GVBasics.Connect] = {
RETURN[ReceiveGVString[str]];
};
SendRemark: PUBLIC PROC [str: Handle, remark: GVBasics.Remark] = {
SendGVString[str, remark];
};
ReceiveRemark: PUBLIC PROC [str: Handle] RETURNS [GVBasics.Remark] = {
RETURN[ReceiveGVString[str]];
};
SendGVString: PUBLIC PROC [str: Handle, rope: GVBasics.GVString] = {
length: INT = rope.Length[];
IF length > GVBasics.maxGVStringLength THEN
ERROR Failed[clientError, "Excessive rope length"];
SendCount[str, length];
SendCount[str, 0--ignored--];
SendRope[str, rope];
IF length MOD 2 # 0 THEN SendByte[str,0];
};
ReceiveFunnyString: PUBLIC PROC [str: Handle] RETURNS [GVBasics.GVString] = TRUSTED {
string: STRING = [GVBasics.maxGVStringLength];
string.length ← ReceiveCount[str];
No maxLength
ReceiveBytes[str, [LOOPHOLE[LONG[@string.text]], 0, bpw*(SIZE[StringBody[string.length]] - SIZE[StringBody[0]])]];
RETURN[ConvertUnsafe.ToRope[string]];
};
ReceiveGVString: PUBLIC PROC [str: Handle] RETURNS [GVBasics.GVString] = TRUSTED {
string: STRING = [GVBasics.maxGVStringLength];
string.length ← ReceiveCount[str];
[] ← ReceiveCount[str]; -- maxLength
IF string.length > string.maxlength THEN
ERROR Failed[protocolError, "Protocol error: too many characters"];
ReceiveBytes[str, [LOOPHOLE[LONG[@string.text]], 0, bpw*(SIZE[StringBody[string.length]] - SIZE[StringBody[0]])]];
RETURN [ConvertUnsafe.ToRope[string]]
};
SendRope: PUBLIC PROC [str: Handle, rope: Rope.ROPE] = {
ENABLE {
PupStream.StreamClosing => ERROR Failed[communicationError, text];
PupStream.Timeout => SIGNAL Failed[noData, "Server not reading data"]; };
IO.PutRope[str, rope];
};
Enquire: PUBLIC PROC [str: Handle, op: GVNames.RSOperation, name: GVBasics.RName, oldStamp: GVBasics.Timestamp ← GVBasics.oldestTime]
RETURNS [rc: GVProtocol.ReturnCode, stamp: GVBasics.Timestamp] = {
SendRSOperation[str, op];
SendRName[str, name];
IF op IN [Expand .. CheckStamp] THEN SendTimestamp[str, oldStamp];
SendNow[str];
rc ← ReceiveRC[str];
IF rc.code = done AND op IN [Expand .. CheckStamp] THEN stamp ← ReceiveTimestamp[str]
ELSE stamp ← oldStamp;
};
ReceiveRList: PUBLIC PROC [str: Handle, work: PROC [GVBasics.RName]] = {
length: INT ← ReceiveCount[str];
WHILE length > 0 DO
name: GVBasics.RName = ReceiveRName[str];
length ← length - StringSize[name];
work[name];
ENDLOOP;
};
}.