GrapevineUser (Cedar) - subroutines for mail and reg server protocols
GVProtocolImpl.mesa
Andrew Birrell 23-Jan-81 17:07:47
Last Edited by: Levin, September 22, 1983 11:59 am
Last Edited by: Birrell, August 25, 1983 5:06 pm
DIRECTORY
Basics USING[ BITSHIFT, BITXOR ],
ConvertUnsafe USING[ ToRope ],
GVBasics USING[ GVString, maxGVStringLength, oldestTime, Password, RName, Timestamp],
GVProtocol USING[ bpw, FailureReason, GVSocket, Handle, ReceiveCount, ReceiveRC, ReceiveRName, ReceiveTimestamp, ReturnCode, RSOperation, SendCount, SendRName, SendRSOperation, SendTimestamp, StringSize ],
IO USING[ EndOfStream, Flush, GetChar, PutChar, PutFR, PutRope, STREAM, UnsafeBlock, UnsafeGetBlock, UnsafePutBlock ],
PupDefs USING[ AnyLocalPupAddress, PupPackageMake, SecondsToTocks ],
PupStream USING[ PupAddress, PupByteStreamCreate, StreamClosing, TimeOut ],
PupTypes USING[ Byte, fillInSocketID, PupAddress, PupSocketID ],
Rope USING[ Fetch, Length, ROPE ];
GVProtocolImpl:
CEDAR
MONITOR
IMPORTS Basics, ConvertUnsafe, GVProtocol, IO, PupDefs, PupStream, Rope
EXPORTS GVBasics, GVProtocol =
BEGIN
OPEN GVProtocol;
MakeKey:
PUBLIC
PROC[password: Rope.
ROPE]
RETURNS[ key: GVBasics.Password ] =
BEGIN
key ← ALL[0];
FOR i: CARDINAL IN CARDINAL[0..password.Length[])
DO j: [0..
LENGTH[key]) = (i/bpw)
MOD
LENGTH[key];
c:
WORD =
LOOPHOLE[
IF password.Fetch[i]
IN ['A..'Z]
THEN password.Fetch[i] - 'A + 'a
ELSE password.Fetch[i] ];
key[j] ← Basics.BITXOR[ key[j], Basics.BITSHIFT[c, IF (i MOD 2) = 0 THEN 9 ELSE 1]];
ENDLOOP;
END;
RopeFromTimestamp:
PUBLIC
PROC[stamp: GVBasics.Timestamp]
RETURNS[Rope.
ROPE] =
{
RETURN[
IO.PutFR["%b#%b@%g",
[integer[stamp.net]], [integer[stamp.host]], [integer[stamp.time]] ] ] };
bpw: INT = GVProtocol.bpw;
sockets:
ARRAY GVProtocol.GVSocket
OF PupTypes.PupSocketID ← [
none: [0,0],
RSEnquiry: [0, 50B],
RSPoll: [0, 52B],
Lily: [0, 53B],
MSPoll: [0, 54B],
MSForward: [0, 55B],
MSSend: [0, 56B],
MSRetrieve: [0, 57B]
];
SetTestingMode:
PUBLIC
ENTRY
PROCEDURE =
BEGIN
FOR s: GVProtocol.GVSocket IN GVProtocol.GVSocket DO sockets[s].a ← 1 ENDLOOP;
END;
GetSocket:
PUBLIC
ENTRY
PROC[gv: GVSocket]
RETURNS[PupTypes.PupSocketID] =
{ RETURN[ sockets[gv] ] };
myAddr: PupTypes.PupAddress;
IsLocal:
PUBLIC
PROCEDURE[addr: PupTypes.PupAddress]
RETURNS[
BOOLEAN ] =
BEGIN
RETURN[ addr.net = myAddr.net AND addr.host = myAddr.host ]
END;
Failed: PUBLIC SIGNAL[why: FailureReason, text: Rope.ROPE] = CODE;
CreateStream:
PUBLIC
PROCEDURE[host: PupTypes.PupAddress, socket: GVProtocol.GVSocket, secs:
CARDINAL ← 120 ]
RETURNS[ GVProtocol.Handle ] =
BEGIN
ENABLE PupStream.StreamClosing => ERROR Failed[communicationError, text];
IF socket # none THEN host.socket ← sockets[socket];
RETURN[ PupStream.PupByteStreamCreate[host, PupDefs.SecondsToTocks[secs] ] ]
END;
SendNow:
PUBLIC
PROCEDURE[ str: GVProtocol.Handle ] =
BEGIN
ENABLE PupStream.StreamClosing => ERROR Failed[communicationError, text];
str.Flush[];
END;
Byte: TYPE = [0..256);
SendByte:
PUBLIC
PROCEDURE[ str: GVProtocol.Handle, byte: Byte ] =
BEGIN
ENABLE PupStream.StreamClosing => ERROR Failed[communicationError, text];
str.PutChar[LOOPHOLE[byte]];
END;
ReceiveByte:
PUBLIC
PROCEDURE[ str: GVProtocol.Handle ]
RETURNS[ byte: Byte ] =
BEGIN
ENABLE
BEGIN
PupStream.StreamClosing => ERROR Failed[communicationError, text];
PupStream.TimeOut => SIGNAL Failed[noData, "Server not sending data"];
IO.EndOfStream => ERROR Failed[protocolError, "Unexpected \"mark\""];
END;
byte ← LOOPHOLE[str.GetChar[]];
END;
SendBytes:
PUBLIC
PROC[str: GVProtocol.Handle, block:
IO.UnsafeBlock] =
BEGIN
ENABLE PupStream.StreamClosing => ERROR Failed[communicationError, text];
str.UnsafePutBlock[block];
END;
ReceiveBytes:
PUBLIC
UNSAFE
PROC[str: GVProtocol.Handle, block:
IO.UnsafeBlock] =
TRUSTED
BEGIN
ENABLE
BEGIN
PupStream.StreamClosing => ERROR Failed[communicationError, text];
PupStream.TimeOut => SIGNAL Failed[noData, "Server not sending data"];
IO.EndOfStream => ERROR Failed[protocolError, "Protocol error: unexpected \"mark\""];
END;
nBytes: INT = str.UnsafeGetBlock[block];
IF nBytes # block.count
THEN ERROR Failed[protocolError, "Protocol error: unexpected \"mark\""];
END;
SendGVString:
PUBLIC
PROC[ str: GVProtocol.Handle, rope: GVBasics.GVString] =
BEGIN
length: INT = rope.Length[];
IF length > GVBasics.maxGVStringLength
THEN ERROR Failed[clientError, "Excessive rope length"];
GVProtocol.SendCount[str, length]; GVProtocol.SendCount[str, 0--ignored--];
SendRope[str, rope];
IF length MOD 2 # 0 THEN SendByte[str,0];
END;
ReceiveGVString:
PUBLIC
PROC[ str: GVProtocol.Handle]
RETURNS[GVBasics.GVString] =
TRUSTED
BEGIN
string: STRING = [GVBasics.maxGVStringLength];
string.length ← GVProtocol.ReceiveCount[str]; [] ← GVProtocol.ReceiveCount[str];
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]]
END;
SendRope:
PUBLIC
PROC[ str: GVProtocol.Handle, rope: Rope.
ROPE] =
BEGIN
str.PutRope[rope ! PupStream.StreamClosing => ERROR Failed[communicationError, text]];
END;
Enquire:
PUBLIC
PROCEDURE[str: GVProtocol.Handle,
op: GVProtocol.RSOperation,
name: GVBasics.RName,
oldStamp: GVBasics.Timestamp ← GVBasics.oldestTime ]
RETURNS[ rc: GVProtocol.ReturnCode, stamp: GVBasics.Timestamp ] =
BEGIN
GVProtocol.SendRSOperation[str, op];
GVProtocol.SendRName[str, name];
IF op IN [Expand .. CheckStamp]
THEN GVProtocol.SendTimestamp[str, oldStamp];
SendNow[str];
rc ← GVProtocol.ReceiveRC[str];
IF rc.code = done
AND op IN [Expand .. CheckStamp]
THEN stamp ← GVProtocol.ReceiveTimestamp[str]
ELSE stamp ← oldStamp;
END;
ReceiveRList:
PUBLIC
PROCEDURE[str: GVProtocol.Handle,
work: PROCEDURE[GVBasics.RName] ] =
BEGIN
length: INT ← ReceiveCount[str];
WHILE length > 0
DO name: GVBasics.RName = GVProtocol.ReceiveRName[str];
length ← length - GVProtocol.StringSize[name];
work[name];
ENDLOOP;
END;
Init:
PROC =
TRUSTED
BEGIN
PupDefs.PupPackageMake[];
myAddr ← PupDefs.AnyLocalPupAddress[PupTypes.fillInSocketID];
END;
Init[];
END.