-- FTPUserMailOut.mesa, Edited by: HGM July 28, 1980 9:29 PM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY FTPDefs, FTPPrivateDefs, String USING [AppendChar, StringToDecimal]; FTPUserMailOut: PROGRAM -- import list IMPORTS String, FTPPrivateDefs -- export list EXPORTS FTPDefs -- share list SHARES FTPDefs, FTPPrivateDefs = BEGIN OPEN FTPDefs, FTPPrivateDefs; -- **********************! Constants !*********************** ftpsystem: POINTER TO FTPSystem = LocateFtpSystemObject[]; -- **********************! Delivery Primitives !*********************** FTPBeginDeliveryOfMessage: PUBLIC PROCEDURE [ftpuser: FTPUser] = BEGIN OPEN ftpuser; -- verify purpose and state VerifyPurposeAndState[ftpuser, mail, connected]; -- If the message gets forwarded, IFSs want to know where to send complains. IF primaryPropertyList[userName] = NIL THEN Abort[credentialsMissing]; -- send store mail command PutCommand[mtper, markStoreMail, 0]; -- initialize number of recipients and valid recipients to zero numberOfRecipients ← numberOfValidRecipients ← 0; -- initialize property list for non-standard use -- Note: FTPSendRecipientOfMessage circumvents WriteProperty -- to avoid allocation and release of main storage in this inner loop. ResetPropertyList[propertyList]; -- note readiness to send recipients state ← messageRecipientsBeingSent; END; FTPSendRecipientOfMessage: PUBLIC PROCEDURE [ ftpuser: FTPUser, mailboxName, mailboxHostName, dmsName: STRING] = BEGIN OPEN ftpuser; propertyList: PropertyList ← ftpuser.propertyList; -- verify purpose and state VerifyPurposeAndState[ftpuser, mail, messageRecipientsBeingSent]; -- store mailbox name in property list -- Note: WriteProperty is circumvented -- to avoid allocation and release of main storage in this inner loop. propertyList[mailbox] ← mailboxName; IF numberOfRecipients = 0 THEN propertyList[sender] ← primaryPropertyList[userName]; -- send the property list PutPropertyList[ mtper, propertyList ! UNWIND => propertyList[mailbox] ← propertyList[sender] ← NIL]; propertyList[mailbox] ← propertyList[sender] ← NIL; -- increment number of recipients and valid recipients numberOfRecipients ← numberOfRecipients + 1; numberOfValidRecipients ← numberOfValidRecipients + 1; END; FTPIdentifyNextRejectedRecipient: PUBLIC PROCEDURE [ ftpuser: FTPUser, errorMessage: STRING] RETURNS [recipientNumber: CARDINAL, recipientError: RecipientError] = BEGIN OPEN ftpuser; -- Note: Returns recipientNumber=0 if no more mailbox exceptions. -- local constants inputString: STRING = mtper.inputString; textualRecipientNumber: STRING = [maxStringLength]; -- local variables mark, code: Byte; string: STRING; i: CARDINAL; shouldBe: UserState; -- verify purpose and state shouldBe ← SELECT state FROM messageRecipientsBeingSent, initialMailboxExceptionsBeingReceived, messageTextBeingSent => state, ENDCASE => finalMailboxExceptionsBeingReceived; VerifyPurposeAndState[ftpuser, mail, shouldBe]; -- signal end of recipient list or text as necessary SELECT state FROM messageRecipientsBeingSent => BEGIN PutEOC[mtper]; state ← initialMailboxExceptionsBeingReceived; END; messageTextBeingSent => BEGIN PutCommandAndEOC[mtper, markYes, 0]; state ← finalMailboxExceptionsBeingReceived; END; ENDCASE; -- fetch next mailbox exception if any [mark, code] ← GetCommand[mtper]; SELECT mark FROM markMailboxException => BEGIN -- separate recipient number and error message string ← textualRecipientNumber; errorMessage.length ← 0; FOR i IN [0..inputString.length) DO IF string = textualRecipientNumber AND inputString[i] = mailboxExceptionIndexTerminator THEN string ← errorMessage ELSE String.AppendChar[string, inputString[i]]; ENDLOOP; -- decode and verify recipient number recipientNumber ← String.StringToDecimal[textualRecipientNumber]; IF recipientNumber ~IN [1..numberOfRecipients] THEN Abort[noSuchRecipientNumber]; -- decode and verify error code recipientError ← ExceptionCodeToRecipientError[code]; -- supply error message if none provided IF errorMessage.length = 0 AND ftpsystem.accessoriesLoaded THEN VerbalizeRecipientError[recipientError, errorMessage]; -- decrement number of valid recipients IF numberOfValidRecipients = 0 THEN Abort[duplicateMailboxException]; numberOfValidRecipients ← numberOfValidRecipients - 1; END; markYes => BEGIN -- receive EOC GetEOC[mtper]; -- lay groundwork for transmission of message IF state = initialMailboxExceptionsBeingReceived THEN BEGIN PutCommand[mtper, markHereIsFile, 0]; state ← messageTextBeingSent; END -- note mail delivery complete ELSE state ← messageDelivered; -- inform caller of end of mailbox exception run recipientNumber ← 0; END; markNo => BEGIN -- receive EOC GetEOC[mtper]; -- note mail delivery complete state ← messageDelivered; -- abort AbortWithExplanation[CodeToSignal[code], inputString]; END; ENDCASE => Abort[illegalProtocolSequence]; END; FTPSendBlockOfMessage: PUBLIC PROCEDURE [ ftpuser: FTPUser, source: POINTER, byteCount: CARDINAL] = BEGIN OPEN ftpuser; -- local variables bytePointerObject: BytePointerObject ← [source, FALSE, byteCount]; -- verify purpose and state VerifyPurposeAndState[ftpuser, mail, messageTextBeingSent]; -- send block of message -- Note: The FTPUtilities procedure, SendBytes, is here replicated in-line -- to reduce Alto working sets. IF bytePointerObject.count > 0 THEN BEGIN OPEN mtper; communicationPrimitives.SendBytes[ communicationSystem, connection, @bytePointerObject]; END; END; FTPEndDeliveryOfMessage: PUBLIC PROCEDURE [ftpuser: FTPUser] = BEGIN OPEN ftpuser; -- verify purpose and state VerifyPurposeAndState[ftpuser, mail, messageDelivered]; -- restore state state ← connected; END; END. -- of FTPUserMailOut