-- file: FTPUserStore.mesa, Edit: HGM July 31, 1980 7:25 PM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY FTPDefs, FTPPrivateDefs, Storage USING [Node, Free]; FTPUserStore: PROGRAM IMPORTS Storage, FTPDefs, FTPPrivateDefs EXPORTS FTPDefs SHARES FTPDefs = BEGIN OPEN FTPDefs, FTPPrivateDefs; FTPStoreFile: PUBLIC PROCEDURE [ ftpuser: FTPUser, localFile, remoteFile: STRING, fileType: FileType] RETURNS [byteCount: LONG INTEGER] = BEGIN OPEN ftpuser; -- local constants bufferSize: CARDINAL = maximumDumpBlockSize + minimumDumpBlockSize; -- local variables creationDate: STRING = [maxDateLength]; writeDate: STRING = [maxDateLength]; readDate: STRING = [maxDateLength]; storeState: {inactive, initiated, waiting, transferring} ← inactive; fileHandle: FileHandle ← NIL; fileInfoObject: FileInfoObject ← [fileType: fileType, byteSize: 0, byteCount: 0, creationDate: creationDate, writeDate: writeDate, readDate: readDate, author: NIL]; dumpStateObject: DumpStateObject ← [bufferAddress: NIL, bufferLength: 0, ftper: ftper, blockType:]; -- verify purpose and state VerifyPurposeAndState[ ftpuser, files, IF state = connected THEN connected ELSE dumpFileBeingSent]; -- intercept errors BEGIN ENABLE UNWIND => BEGIN ENABLE FTPError => IF ftpError IN CommunicationError THEN CONTINUE; IF dumpStateObject.bufferAddress # NIL THEN Storage.Free[dumpStateObject.bufferAddress]; IF fileHandle # NIL THEN filePrimitives.CloseFile[ftpuser.fileSystem, fileHandle, TRUE]; IF storeState = initiated THEN SELECT GetCommand[ftper].mark FROM markHereIsPropertyList => BEGIN GetPropertyList[ftper, propertyList]; GetEOC[ftper]; storeState ← transferring; END; markNo => GetEOC[ftper]; ENDCASE; --illegalProtocolSequence IF storeState = transferring THEN BEGIN PutCommandAndEOC[ftper, markNo, codeFileDataError]; GetSpecificCommand[ftper, markNo]; GetEOC[ftper]; END; END; -- determine file type if necessary [fileHandle, fileInfoObject.fileType] ← filePrimitives.OpenFile[ ftpuser.fileSystem, localFile, read, fileType = unknown, @fileInfoObject]; -- initiate remote store IF state = connected THEN BEGIN -- send store command PutCommand[ftper, markNewStore, 0]; -- construct property list containing absolute and virtual filenames, credentials, and file information ResetPropertyList[propertyList]; WriteFilename[remoteFile, propertyList, NIL, NIL, primaryPropertyList]; IF fileType # unknown THEN fileInfoObject.fileType ← fileType; fileInfoObject.byteSize ← IF fileInfoObject.fileType = binary THEN 8 ELSE 0; WriteFileInfo[propertyList, @fileInfoObject]; -- send property list and EOC PutPropertyList[ftper, propertyList]; PutEOC[ftper]; -- note store initiated storeState ← initiated; END; -- sustain remote store IF state = connected THEN BEGIN -- note waiting to transfer storeState ← waiting; -- sustain remote store GetSpecificCommand[ftper, markHereIsPropertyList]; GetPropertyList[ftper, propertyList]; GetEOC[ftper]; -- signal transmission of file PutCommand[ftper, markHereIsFile, 0]; -- note transfer in progress storeState ← transferring; END; -- send the file byteCount ← ftper.totalByteCount; IF state = connected THEN filePrimitives.ReadFile[ftpuser.fileSystem, fileHandle, SendBlock, ftper] ELSE BEGIN SendHeaderBlock[@dumpStateObject, remoteFile, creationDate]; -- allocate a buffer dumpStateObject.bufferAddress ← Storage.Node[bufferSize]; -- send the file filePrimitives.ReadFile[ ftpuser.fileSystem, fileHandle, DumpBlock, @dumpStateObject]; -- release the buffer Storage.Free[dumpStateObject.bufferAddress]; dumpStateObject.bufferAddress ← NIL; END; byteCount ← ftper.totalByteCount - byteCount; -- terminate remote store IF state = connected THEN BEGIN -- send Yes and EOC PutCommandAndEOC[ftper, markYes, 0]; storeState ← waiting; -- close local file -- Note: Closing of the local file is deferred -- until end-of-file has been sent to the remote server -- so that closing of the local and remote files can be overlapped. filePrimitives.CloseFile[ftpuser.fileSystem, fileHandle, FALSE]; fileHandle ← NIL; -- receive acknowledgment GetYesAndEOC[ftper]; END -- close local file ELSE filePrimitives.CloseFile[ftpuser.fileSystem, fileHandle, FALSE]; END; -- enable END; END. -- of FTPUserStore