-- Transport Mechanism: User: MTP retrieval -- [Juniper]<Grapevine>User>RetrieveMTP.mesa -- Mike Schroeder 13-Nov-80 17:04:12 -- Andrew Birrell 8-Sep-82 15:12:09 DIRECTORY BodyDefs USING [ItemHeader], FTPDefs USING [CommunicationError, CredentialError, FTPBeginRetrievalOfMessages, FTPCreateUser, FTPDestroyUser, FTPEndRetrievalOfMessages, FTPError, FTPIdentifyNextMessage, FTPInitialize, FTPOpenConnection, FTPRetrieveBlockOfMessage, FTPSetCredentials, MailError, MessageInfoObject, PupCommunicationPrimitives], PupDefs USING [AppendPupAddress], RetrieveDefs USING [Failed], RetrieveXDefs USING [Handle, ServerAddress]; RetrieveMTP: MONITOR LOCKS handle USING handle: RetrieveXDefs.Handle IMPORTS FTPDefs, PupDefs, RetrieveDefs, RetrieveXDefs EXPORTS RetrieveXDefs = BEGIN OPEN FTPDefs; MTPNextMessage: PUBLIC ENTRY PROCEDURE [handle:RetrieveXDefs.Handle] RETURNS [msgExists:BOOLEAN, archived:BOOLEAN, deleted:BOOLEAN] = BEGIN ENABLE UNWIND => NULL; dateString: STRING = [40]; -- arbitrary number, but big enough! -- m: MessageInfoObject ← [byteCount:, deliveryDate:dateString, opened:, deleted:]; SELECT handle.state FROM end => ERROR; beginning => BEGIN addressString: STRING = [22]--377#377#177777|177777--; handle.ftpUser ← FTPCreateUser[NIL, PupCommunicationPrimitives[]]; FTPSetCredentials[handle.ftpUser, primary, handle.userName, handle.userPwd]; PupDefs.AppendPupAddress[addressString, RetrieveXDefs.ServerAddress[handle]]; FTPOpenConnection[handle.ftpUser, addressString, mail, NIL ! FTPError => BEGIN handle.state ← end; SELECT ftpError FROM noSuchHost => ERROR RetrieveDefs.Failed[noSuchServer]; connectionRejected => ERROR RetrieveDefs.Failed[connectionRejected]; IN CommunicationError => ERROR RetrieveDefs.Failed[communicationFailure]; ENDCASE => ERROR RetrieveDefs.Failed[unknownFailure]; END ]; FTPBeginRetrievalOfMessages[handle.ftpUser, handle.userName ! FTPError => BEGIN handle.state ← end; SELECT ftpError FROM IN CredentialError, IN MailError => ERROR RetrieveDefs.Failed[badCredentials]; unidentifiedTransientError, fileBusy => --mailbox busy ERROR RetrieveDefs.Failed[connectionRejected]; IN CommunicationError => ERROR RetrieveDefs.Failed[communicationFailure]; ENDCASE => ERROR RetrieveDefs.Failed[unknownFailure]; END ]; END; ENDCASE; FTPIdentifyNextMessage[handle.ftpUser, @m ! FTPError => BEGIN handle.state ← end; ERROR RetrieveDefs.Failed[IF ftpError IN CommunicationError THEN communicationFailure ELSE unknownFailure]; END ]; msgExists ← m.byteCount#0; deleted ← m.deleted; archived ← FALSE; handle.header.length ← m.byteCount; handle.header.type ← Text; handle.state ← IF msgExists THEN message ELSE lastMessage; END; --NextMessage-- MTPNextItem: PUBLIC ENTRY PROCEDURE [handle:RetrieveXDefs.Handle] RETURNS [itemHeader:BodyDefs.ItemHeader] = BEGIN ENABLE UNWIND => NULL; SELECT handle.state FROM message => {itemHeader ← handle.header; handle.state ← block; handle.spareByte ← FALSE}; block, lastBlock => {itemHeader ← [LastItem, 0]; handle.state← lastBlock}; ENDCASE => ERROR; END; --NextMessage-- MTPNextBlock: PUBLIC ENTRY PROCEDURE [handle:RetrieveXDefs.Handle, buffer:DESCRIPTOR FOR PACKED ARRAY OF CHARACTER] RETURNS[bytes:CARDINAL] = BEGIN ENABLE UNWIND => NULL; SELECT handle.state FROM block => BEGIN -- much of this code is dedicated to the design of FTPDefs. -- -- "handle" may contain an extra byte from previous call -- IF handle.spareByte THEN BEGIN buffer[0] ← handle.spareByteValue; handle.spareByte ← FALSE; bytes ← 1; END ELSE bytes ← 0; WHILE bytes < LENGTH[buffer] DO extraWord: PACKED ARRAY[0..1] OF CHARACTER; bWordsUsed: CARDINAL =(bytes+1)/2; firstFree: POINTER = BASE[buffer]+bWordsUsed; bWordsFree: CARDINAL = LENGTH[buffer]/2-bWordsUsed; base: POINTER = IF bWordsFree = 0 THEN @extraWord ELSE firstFree; length: CARDINAL = IF bWordsFree = 0 THEN LENGTH[extraWord]/2 ELSE bWordsFree; given: CARDINAL = FTPRetrieveBlockOfMessage[handle.ftpUser, base, length ! FTPError => BEGIN handle.state ← end; ERROR RetrieveDefs.Failed[IF ftpError IN CommunicationError THEN communicationFailure ELSE unknownFailure]; END ]; IF given = 0 THEN { handle.state ← lastBlock; EXIT }; IF bWordsFree = 0 THEN BEGIN -- data was placed in extraWord -- buffer[bytes] ← extraWord[0]; bytes ← bytes + 1; IF given > 1 THEN BEGIN handle.spareByteValue ← extraWord[1]; handle.spareByte ← TRUE; END; END ELSE BEGIN -- data was placed in buffer -- IF bytes MOD 2 # 0 THEN FOR i: CARDINAL IN [bytes..bytes+given) DO buffer[i] ← buffer[i+1]; ENDLOOP; bytes ← bytes+given; END; ENDLOOP; END; lastBlock => bytes ← 0; ENDCASE => ERROR; END; --NextBlock-- MTPAccept: PUBLIC INTERNAL PROCEDURE [handle:RetrieveXDefs.Handle] = BEGIN IF handle.state # lastMessage THEN ERROR; handle.state ← end; FTPEndRetrievalOfMessages[handle.ftpUser ! FTPError => ERROR RetrieveDefs.Failed[IF ftpError IN CommunicationError THEN communicationFailure ELSE unknownFailure] ]; END; --Accept-- MTPClose: PUBLIC INTERNAL PROCEDURE [handle:RetrieveXDefs.Handle] = BEGIN IF handle.ftpUser # NIL THEN BEGIN FTPDestroyUser[handle.ftpUser]; handle.ftpUser ← NIL; handle.state ← beginning; END; END; --Close-- FTPInitialize[]; END. -- RetrieveMTP--