-- 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