-- GrapevineUser (Cedar) - retrieval of messages -- GVRetrieveImpl.mesa -- Andrew Birrell September 1, 1982 10:15 am DIRECTORY BodyDefs USING[ maxRNameLength, RName], ConvertUnsafe USING[ AppendRope, ToRope ], GVBasics USING[ ItemHeader, RName, Timestamp ], GVRetrieve USING[], PupStream USING[ StreamClosing ], RetrieveDefs, RetrieveXDefs USING[ Handle ], Rope USING[ Cat, Length, ROPE, Substr ], Stream USING[ CompletionCode, GetBlock, SubSequenceType, TimeOut ]; GVRetrieveImpl: CEDAR MONITOR LOCKS handle USING handle: Handle IMPORTS ConvertUnsafe, RetrieveDefs, Rope, PupStream, Stream EXPORTS GVRetrieve = BEGIN ROPE: TYPE = Rope.ROPE; Handle: TYPE = REF Object; Object: PUBLIC TYPE = MONITORED RECORD[ h: RetrieveDefs.Handle, p: RetrieveDefs.AccessProcs _ NULL]; Create: PUBLIC PROC[pollingInterval: CARDINAL, reportChanges: PROCEDURE[RetrieveDefs.MBXState] _ NIL] RETURNS[Handle] = TRUSTED BEGIN RETURN[NEW[Object _ [h: RetrieveDefs.Create[pollingInterval, reportChanges]]]] END; Close: PUBLIC ENTRY PROC[handle: Handle] = TRUSTED { RetrieveDefs.Destroy[handle.h]; handle.h _ LOOPHOLE[NIL]--sorry!-- }; NewUser: PUBLIC PROC[ handle: Handle, user: GVBasics.RName, password: ROPE] = TRUSTED BEGIN u: BodyDefs.RName = [BodyDefs.maxRNameLength]; p: STRING = [64]; ConvertUnsafe.AppendRope[p,password]; IF Rope.Length[user] <= BodyDefs.maxRNameLength THEN ConvertUnsafe.AppendRope[u, user]; --ELSE leave "u" empty, which is an invalid user name -- RetrieveDefs.NewUser[handle.h, u, p]; END; MailboxState: PUBLIC PROC[ handle: Handle] RETURNS[ state: RetrieveDefs.MBXState] = TRUSTED { RETURN[ RetrieveDefs.MailboxState[handle.h] ] }; WaitForMail: PUBLIC PROC[ handle: Handle ] = TRUSTED { RetrieveDefs.WaitForMail[handle.h] }; NextServer: PUBLIC ENTRY PROC[ handle: Handle ] RETURNS[ noMore: BOOLEAN, state: RetrieveDefs.ServerState, type: RetrieveDefs.ServerType ] = TRUSTED BEGIN [noMore, state, handle.p] _ RetrieveDefs.NextServer[handle.h]; type _ handle.p.type; END; ServerName: PUBLIC PROC[ handle: Handle] RETURNS [serverName: GVBasics.RName] = TRUSTED BEGIN n: BodyDefs.RName = [BodyDefs.maxRNameLength]; RetrieveDefs.ServerName[handle.h, n]; RETURN[ConvertUnsafe.ToRope[n]] END; Failed: PUBLIC ERROR[why: RetrieveDefs.FailureReason] = CODE; NotAvailableForMTPServer: ERROR = CODE; NextMessage: PUBLIC ENTRY PROC[handle: Handle] RETURNS[msgExists, archived, deleted: BOOLEAN] = TRUSTED BEGIN ENABLE { RetrieveDefs.Failed => ERROR Failed[why]; UNWIND => NULL }; [msgExists, archived, deleted] _ handle.p.nextMessage[handle.h]; -- signals if MTP -- END; StartMessage: PUBLIC ENTRY PROC[handle: Handle ] RETURNS[postmark: GVBasics.Timestamp, sender: GVBasics.RName, returnTo: GVBasics.RName] = TRUSTED BEGIN ENABLE { RetrieveDefs.Failed => ERROR Failed[why]; UNWIND => NULL }; s: BodyDefs.RName = [BodyDefs.maxRNameLength]; r: BodyDefs.RName = [BodyDefs.maxRNameLength]; WITH p: handle.p SELECT FROM GV => p.startMessage[handle.h, @postmark, s, r]; MTP => ERROR NotAvailableForMTPServer[]; ENDCASE => ERROR; RETURN[postmark, ConvertUnsafe.ToRope[s], ConvertUnsafe.ToRope[r]] END; NextItem: PUBLIC ENTRY PROC[handle: Handle] RETURNS[GVBasics.ItemHeader] = TRUSTED BEGIN ENABLE { RetrieveDefs.Failed => ERROR Failed[why]; UNWIND => NULL }; RETURN[ handle.p.nextItem[handle.h] ] END; NextBlock: PUBLIC ENTRY PROC[handle: Handle, maxlength: INT] RETURNS[block: ROPE] = TRUSTED BEGIN ENABLE { RetrieveDefs.Failed => ERROR Failed[why]; UNWIND => NULL }; wanted: INT _ maxlength; block _ NIL; WHILE wanted > 0 DO sLength: CARDINAL = 120; -- non-critical number; choose to ensure small frame -- s: STRING = [sLength]; limit: CARDINAL = MIN[wanted, sLength]; s.length _ handle.p.nextBlock[handle.h, DESCRIPTOR[@s.text, limit]]; IF s.length = 0 THEN EXIT; -- end of item -- block _ Rope.Cat[block, ConvertUnsafe.ToRope[s]]; wanted _ wanted - s.length; ENDLOOP; END; WrongCallSequence: ERROR = CODE; ReadingBeyondEndOfItem: ERROR = CODE; GetBlock: PUBLIC ENTRY PROC[handle: Handle, block: REF TEXT, startIndex: NAT, stopIndexPlusOne: NAT] RETURNS[nBytesRead: NAT] = TRUSTED BEGIN ENABLE UNWIND => NULL; lowHandle: RetrieveXDefs.Handle = LOOPHOLE[handle.h]; -- sigh! -- why: Stream.CompletionCode; sst: Stream.SubSequenceType; IF lowHandle.state # inBody THEN ERROR WrongCallSequence[]; [nBytesRead, why, sst] _ Stream.GetBlock[lowHandle.currentStr, [ @block.text + SIZE[CARDINAL], startIndex, MIN[startIndex+lowHandle.header.length, stopIndexPlusOne]] ! PupStream.StreamClosing, Stream.TimeOut => ERROR Failed[communicationFailure] ]; IF why # normal THEN ERROR; lowHandle.header.length _ lowHandle.header.length - nBytesRead; END; GetChar: PUBLIC ENTRY PROC[handle: Handle] RETURNS[CHAR] = TRUSTED BEGIN ENABLE UNWIND => NULL; lowHandle: RetrieveXDefs.Handle = LOOPHOLE[handle.h]; -- sigh! -- why: Stream.CompletionCode; sst: Stream.SubSequenceType; buffer: PACKED ARRAY [0..1] OF CHAR; nBytesRead: CARDINAL; IF lowHandle.state # inBody THEN ERROR WrongCallSequence[]; IF lowHandle.header.length = 0 THEN ERROR ReadingBeyondEndOfItem[]; [nBytesRead, why, sst] _ Stream.GetBlock[lowHandle.currentStr, [ @buffer, 0, 1] ! PupStream.StreamClosing, Stream.TimeOut => ERROR Failed[communicationFailure] ]; IF why # normal THEN ERROR; IF nBytesRead # 1 THEN ERROR; lowHandle.header.length _ lowHandle.header.length - nBytesRead; RETURN[buffer[0]] END; CharsAvail: PUBLIC ENTRY PROC[handle: Handle] RETURNS[BOOL] = TRUSTED BEGIN lowHandle: RetrieveXDefs.Handle = LOOPHOLE[handle.h]; -- sigh! -- RETURN[lowHandle.header.length # 0] END; Accept: PUBLIC ENTRY PROC[handle: Handle] = TRUSTED BEGIN ENABLE { RetrieveDefs.Failed => ERROR Failed[why]; UNWIND => NULL }; handle.p.accept[handle.h]; END; ReadTOC: PUBLIC ENTRY PROC[handle: Handle] RETURNS[ ROPE ] = TRUSTED BEGIN ENABLE { RetrieveDefs.Failed => ERROR Failed[why]; UNWIND => NULL }; t: BodyDefs.RName = [BodyDefs.maxRNameLength]; WITH p: handle.p SELECT FROM GV => p.readTOC[handle.h, t]; MTP => ERROR NotAvailableForMTPServer[]; ENDCASE => ERROR; RETURN[ConvertUnsafe.ToRope[t]] END; WriteTOC: PUBLIC ENTRY PROC[handle: Handle, entry: ROPE ] = TRUSTED BEGIN ENABLE { RetrieveDefs.Failed => ERROR Failed[why]; UNWIND => NULL }; t: BodyDefs.RName = [BodyDefs.maxRNameLength]; ConvertUnsafe.AppendRope[t, Rope.Substr[entry, 0, BodyDefs.maxRNameLength]]; WITH p: handle.p SELECT FROM GV => p.writeTOC[handle.h, t]; MTP => ERROR NotAvailableForMTPServer[]; ENDCASE => ERROR; END; DeleteMessage: PUBLIC ENTRY PROC[handle: Handle] = TRUSTED BEGIN ENABLE { RetrieveDefs.Failed => ERROR Failed[why]; UNWIND => NULL }; WITH p: handle.p SELECT FROM GV => p.deleteMessage[handle.h]; MTP => ERROR NotAvailableForMTPServer[]; ENDCASE => ERROR; END; END.