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; mailDrop: Rope.ROPE _ "MailDrop.MS"; serverKnown: BOOLEAN _ FALSE; serverAddr: PupDefs.PupAddress; SetMailDropList: PUBLIC PROC [list: Rope.ROPE] = BEGIN mailDrop _ list; serverKnown _ FALSE; END; 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, 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[]; 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. fGVSendImpl.mesa: sending mail Copyright c 1985 by Xerox Corporation. All rights reserved. Andrew Birrell May 16, 1983 2:19 pm Willie-Sue, February 27, 1985 10:17:05 am PST Hal Murray May 2, 1985 5:00:17 pm PDT Name for list of servers used to inject mail into the system cached server address SendNow to give better error if connection has gone away ΚΡ˜codešœ™Kšœ Οmœ1™—Kšžœ,žœžœ˜?Kšžœ˜Kšž˜—Kšžœ˜Kšžœ žœ˜)Kšžœ˜K˜—š Ÿ œžœžœžœž˜>K˜K˜—šŸœžœžœžœ˜?Kšž˜Kšœžœ˜ Kšžœžœ ˜Kšžœžœ˜KšžœIžœ ˜[šžœ ˜Kšž˜šŸœžœžœžœ˜9Kšž˜KšœBžœ˜KKšœžœ˜&Kšžœžœ˜ Kšžœžœžœ˜Kšžœ˜—˜"Kšœ-˜-—Kšžœ˜Kš žœžœžœžœžœ˜:Kšžœ˜—Kšžœ˜K˜—šŸ œžœžœžœ-˜LKšž˜šž˜Kšž˜Kšœžœ%žœ˜EKšžœ˜Kšžœ˜—Kšžœžœžœ˜9Kšžœ.žœ˜QK˜5K˜,Kšžœ˜K˜—šŸ œžœžœžœ˜0Kšœžœžœ˜#Kšžœžœ˜Kšž˜šž˜Kšž˜Kšœžœ$žœ˜DKšžœ˜Kšžœ˜—Kšžœžœžœ˜9K˜6K˜šžœžœ'˜0Kšžœžœžœ˜K˜/—Kšžœ˜K˜)K˜Kšžœ˜K˜—šŸ œžœžœžœ+˜GKšž˜šž˜Kšž˜Kšœžœ$žœ˜DKšžœ˜Kšžœ˜—Kšžœžœ˜5Kšžœžœ˜4Kšžœžœžœ˜8K˜2Kšœ!žœ˜1K˜Kšžœ˜K˜—šŸ œžœžœžœ˜,Kšœ žœ˜Kšž˜šž˜Kšž˜Kšœžœ$žœ˜DKšžœ˜Kšžœ˜—Kšžœžœžœ˜8K˜2Kšœ2˜2Kšœ(˜(Kšžœ˜K˜—šŸœžœžœžœ˜)Kšž˜Kšžœžœ˜Kšžœžœ˜5Kšžœžœžœ˜8Kšœ8™8šœ˜Kšœžœ$žœ˜G—šž˜Kšžœžœ$žœ˜LK˜-K˜K˜"—Kšžœ˜K˜K˜Kšžœ˜K˜—šŸœžœžœžœ˜*K˜K˜—šŸœžœžœ˜&Kšž˜Kšžœžœžœ˜6Kšœ žœ˜K˜Kšžœ˜K˜—Kš œžœžœ žœžœ˜2K˜šŸœžœžœžœ˜EKšžœ˜"Kšž˜K˜%Kšžœž˜ Kšžœ˜šžœž˜ šžœ˜Kšž˜Kšœžœ˜.Kšžœ˜ Kšžœ˜—Kšžœ,˜.Kšžœ˜šžœž˜ Kšœ(˜(K˜ K˜Kšžœ˜$Kšžœ$žœ˜.Kšœžœ˜-Kšžœ˜—Kšœ˜Kšžœ˜—Kšžœ˜K˜—Kšžœ˜K˜—…—f#