DIRECTORY GVBasics USING [ItemType, MakeKey, maxRNameLength, Password, RName], GVLocate USING [FindNearestServer, FoundServerInfo], GVProtocol USING [Close, CreateStream, Failed, Handle, ReceiveAck, ReceiveBoolean, ReceiveByte, ReceiveCount, ReceiveRName, SendBoolean, SendCount, SendMSOperation, SendNow, SendPassword, SendBytes, SendRName, SendRope], GVSend USING [ExpandInfo, StartSendInfo], PupDefs USING [PupAddress], Rope USING [Length, ROPE]; GVSendImpl: CEDAR MONITOR IMPORTS GVBasics, GVLocate, GVProtocol, Rope EXPORTS GVSend = BEGIN Handle: TYPE = REF Object; Object: PUBLIC TYPE = RECORD[ state: {idle, started, noItem, inItem} _ idle, str: GVProtocol.Handle _ NIL ]; Create: PUBLIC PROC RETURNS[handle: Handle] = BEGIN handle _ NEW[Object]; END; SendFailed: PUBLIC ERROR[why: Rope.ROPE, notDelivered: BOOLEAN] = CODE; WrongCallSequence: ERROR = CODE; -- cached server address -- serverKnown: BOOLEAN _ FALSE; serverAddr: PupDefs.PupAddress; StartSend: PUBLIC PROC[handle: Handle, senderPwd: Rope.ROPE, sender: GVBasics.RName, returnTo: GVBasics.RName _ NIL, validate: BOOLEAN ] RETURNS[ info: GVSend.StartSendInfo ] = BEGIN info _ SendFromClient[handle, 0, 0, GVBasics.MakeKey[senderPwd], sender, IF returnTo = NIL THEN sender ELSE returnTo, validate]; END; SendFromClient: PUBLIC ENTRY PROC[handle: Handle, fromNet: [0..256), fromHost: [0..256), senderKey: GVBasics.Password, sender: GVBasics.RName, returnTo: GVBasics.RName, validate: BOOLEAN ] RETURNS[ info: GVSend.StartSendInfo ] = BEGIN ENABLE UNWIND => Close[handle]; IF handle.state # idle THEN ERROR WrongCallSequence[]; IF sender.Length[] > GVBasics.maxRNameLength THEN RETURN[badSender]; IF returnTo.Length[] > GVBasics.maxRNameLength THEN RETURN[badReturnTo]; DO handle.str _ InnerGetStream[]; IF handle.str=NIL THEN { info _ allDown; EXIT }; BEGIN ENABLE GVProtocol.Failed => GOTO wentDown; GVProtocol.SendMSOperation[handle.str, startSend]; GVProtocol.SendRName[handle.str, sender]; GVProtocol.SendPassword[handle.str, senderKey]; GVProtocol.SendRName[handle.str, returnTo]; GVProtocol.SendBoolean[handle.str, validate]; GVProtocol.SendNow[handle.str]; TRUSTED {info _ LOOPHOLE[GVProtocol.ReceiveByte[handle.str]]}; EXITS wentDown => { Close[handle]; serverKnown _ FALSE; LOOP }; END; EXIT ENDLOOP; IF info = ok THEN handle.state _ started; END; GetStream: ENTRY PROC RETURNS[str: GVProtocol.Handle] = INLINE { str _ InnerGetStream[] }; InnerGetStream: INTERNAL PROC RETURNS[str: GVProtocol.Handle] = BEGIN str _ NIL; IF NOT serverKnown THEN GOTO noCache ELSE str _ GVProtocol.CreateStream[serverAddr, MSSend ! GVProtocol.Failed => GOTO noCache]; EXITS noCache => BEGIN Accept: PROC[addr: PupDefs.PupAddress] RETURNS[BOOLEAN] = BEGIN str _ GVProtocol.CreateStream[addr, MSSend ! GVProtocol.Failed => GOTO no]; serverKnown _ TRUE; serverAddr _ addr; RETURN[TRUE]; EXITS no => RETURN[FALSE] END; server: GVLocate.FoundServerInfo = GVLocate.FindNearestServer["Maildrop.MS", Accept]; IF server.t # found THEN { IF str#NIL THEN GVProtocol.Close[str]; str _ NIL }; END; END; AddRecipient: PUBLIC ENTRY PROC[handle: Handle, recipient: GVBasics.RName] = BEGIN ENABLE BEGIN GVProtocol.Failed => ERROR SendFailed[why: text, notDelivered: TRUE]; UNWIND => Close[handle]; END; IF handle.state # started THEN ERROR WrongCallSequence[]; IF recipient.Length[] > GVBasics.maxRNameLength THEN recipient _ "Name too long"; GVProtocol.SendMSOperation[handle.str, addRecipient]; GVProtocol.SendRName[handle.str, recipient]; END; CheckValidity: PUBLIC ENTRY PROC[handle: Handle, notify: PROC[INT, GVBasics.RName] ] RETURNS[ ok: INT ] = BEGIN ENABLE BEGIN GVProtocol.Failed => ERROR SendFailed[why: text, notDelivered:TRUE]; UNWIND => Close[handle]; END; IF handle.state # started THEN ERROR WrongCallSequence[]; GVProtocol.SendMSOperation[handle.str, checkValidity]; GVProtocol.SendNow[handle.str]; DO n: INT = GVProtocol.ReceiveCount[handle.str]; IF n = 0 THEN EXIT; notify[n, GVProtocol.ReceiveRName[handle.str]]; ENDLOOP; ok _ GVProtocol.ReceiveCount[handle.str]; handle.state _ noItem; END; StartItem: PUBLIC ENTRY PROC[handle: Handle, type: GVBasics.ItemType] = BEGIN ENABLE BEGIN GVProtocol.Failed => ERROR SendFailed[why: text, notDelivered:TRUE]; UNWIND => Close[handle]; END; IF handle.state = started THEN handle.state _ inItem; IF handle.state = inItem THEN handle.state _ noItem; IF handle.state # noItem THEN ERROR WrongCallSequence[]; GVProtocol.SendMSOperation[handle.str, startItem]; GVProtocol.SendCount[handle.str, LOOPHOLE[type]]; handle.state _ inItem; END; AddToItem: PUBLIC ENTRY PROC[handle: Handle, buffer: Rope.ROPE ] = BEGIN ENABLE BEGIN GVProtocol.Failed => ERROR SendFailed[why: text, notDelivered:TRUE]; UNWIND => Close[handle]; END; IF handle.state # inItem THEN ERROR WrongCallSequence[]; GVProtocol.SendMSOperation[handle.str, addToItem]; GVProtocol.SendCount[handle.str, buffer.Length[]]; GVProtocol.SendRope[handle.str, buffer]; END; Send: PUBLIC ENTRY PROC[handle: Handle] = BEGIN ENABLE UNWIND => Close[handle]; IF handle.state = started THEN handle.state _ inItem; IF handle.state # inItem THEN ERROR WrongCallSequence[]; -- SendNow to give better error if connection has gone away -- GVProtocol.SendNow[handle.str ! GVProtocol.Failed => ERROR SendFailed[why: text, notDelivered:TRUE] ]; BEGIN ENABLE GVProtocol.Failed => ERROR SendFailed[why: text, notDelivered:FALSE]; GVProtocol.SendMSOperation[handle.str, send]; GVProtocol.SendNow[handle.str]; GVProtocol.ReceiveAck[handle.str]; END; Close[handle]; handle.state _ idle; END; Abort: PUBLIC ENTRY PROC[handle: Handle] = { Close[handle] }; Close: INTERNAL PROC[handle: Handle] = BEGIN IF handle.str # NIL THEN GVProtocol.Close[handle.str]; handle.str _ NIL; handle.state _ idle; END; ExpandFailed: PUBLIC ERROR[why: Rope.ROPE] = CODE; Expand: PUBLIC PROC[name: GVBasics.RName, work: PROC[GVBasics.RName]] RETURNS[info: GVSend.ExpandInfo] = BEGIN str: GVProtocol.Handle = GetStream[]; IF str = NIL THEN info _ allDown ELSE BEGIN ENABLE BEGIN GVProtocol.Failed => ERROR ExpandFailed[text]; UNWIND => GVProtocol.Close[str]; END; IF Rope.Length[name] > GVBasics.maxRNameLength THEN info _ notFound ELSE BEGIN GVProtocol.SendMSOperation[str, expand]; GVProtocol.SendRName[str, name]; GVProtocol.SendNow[str]; WHILE GVProtocol.ReceiveBoolean[str] DO work[GVProtocol.ReceiveRName[str]] ENDLOOP; info _ LOOPHOLE[GVProtocol.ReceiveByte[str]]; END; GVProtocol.Close[str]; END; END; END. `GrapevineUser (Cedar): sending mail GVSendImpl.mesa Andrew Birrell May 16, 1983 2:19 pm Êw˜Jšœ#™#Jšœ™Jšœ$™$J˜šÏk ˜ Jšœ œ6˜DJšœ œ&˜4Jšœ œÌ˜ÜJšœœ˜)Jšœœ˜Jšœœ œ˜—J˜šœ œ˜Jšœ%˜,Jšœ ˜—J˜Jš˜J˜Jšœœœ˜J˜šœœœœ˜J˜.Jšœœ˜!J˜—šÏnœœœœ˜-Jš˜Jšœ œ ˜Jšœ˜J˜—Jš œ œœ œœœ˜GJ˜Jšœœœ˜ J˜J˜JšÏc˜Jšœ œœ˜J˜ J˜šž œœœ˜&Jšœœ˜J˜Jšœœ˜Jšœ œ˜Jšœ ˜'Jš˜˜J˜J˜J˜Jšœ œœœ ˜,J˜ —Jšœ˜J˜J˜—šžœœœœ˜1J˜&J˜J˜J˜Jšœ œ˜Jšœ ˜'Jš˜Jšœœ˜Jšœœœ˜6Jšœ+œœ ˜DJšœ-œœ˜Hšœ˜!Jšœ œœœ˜0š˜Jšœœ ˜*J˜2J˜)J˜/J˜+J˜-J˜Jšœ œ&˜>—Jšœ,œœ˜?Jšœ˜Jš˜—Jšœ˜Jšœ œ˜)Jšœ˜J˜—š ž œœœœ˜>J˜J˜—šžœœœœ˜?Jš˜Jšœœ˜ Jšœœ ˜Jšœœ˜JšœIœ ˜[šœ ˜Jš˜šžœœœœ˜9Jš˜JšœBœ˜KJšœœ˜&Jšœœ˜ Jšœœœ˜Jšœ˜—˜"J˜2—Jšœ˜Jš œœœœœ˜:Jšœ˜—Jšœ˜J˜—šž œœœœ-˜LJš˜š˜Jš˜Jšœœ%œ˜EJšœ˜Jšœ˜—Jšœœœ˜9Jšœ.œ˜QJ˜5J˜,Jšœ˜J˜—šž œœœœ˜0Jšœœœ˜#Jšœœ˜Jš˜š˜Jš˜Jšœœ$œ˜DJšœ˜Jšœ˜—Jšœœœ˜9J˜6J˜šœœ'˜0Jšœœœ˜J˜/—Jšœ˜J˜)J˜Jšœ˜J˜—šž œœœœ+˜GJš˜š˜Jš˜Jšœœ$œ˜DJšœ˜Jšœ˜—Jšœœ˜5Jšœœ˜4Jšœœœ˜8J˜2Jšœ!œ˜1J˜Jšœ˜J˜—šž œœœœ˜,Jšœ œ˜Jš˜š˜Jš˜Jšœœ$œ˜DJšœ˜Jšœ˜—Jšœœœ˜8J˜2Jšœ2˜2Jšœ(˜(Jšœ˜J˜—šžœœœœ˜)Jš˜Jšœœ˜Jšœœ˜5Jšœœœ˜8JšŸ>˜>šœ˜Jšœœ$œ˜G—š˜Jšœœ$œ˜LJ˜-J˜J˜"—Jšœ˜J˜J˜Jšœ˜J˜—šžœœœœ˜*J˜J˜—šžœœœ˜&Jš˜Jšœœœ˜6Jšœ œ˜J˜Jšœ˜J˜—Jš œœœ œœ˜2J˜šžœœœœ˜EJšœ˜"Jš˜J˜%Jšœ˜ Jšœ˜šœ˜ šœ˜Jš˜Jšœœ˜.Jšœ˜ Jšœ˜—Jšœ,˜.Jšœ˜šœ˜ Jšœ(˜(J˜ J˜Jšœ˜$Jšœ$œ˜.Jšœœ˜-Jšœ˜—Jšœ˜Jšœ˜—Jšœ˜J˜—Jšœ˜J˜—…—<"