-- Transport Mechanism: User: MTP retrieval -- [Juniper]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--