-- Copyright (C) 1979, 1980, 1984, 1985  by Xerox Corporation. All rights reserved. 
-- FTPDefs.mesa, HGM, 15-Sep-85 13:20:00  


FTPDefs: DEFINITIONS =
  BEGIN

  -- **********************!  Version  !***********************

  ftpMajorVersion: Byte = 7;
  ftpMinorVersion: Byte = 0;

  -- **********************!  File System  !***********************

  -- file types
  FileSystem: TYPE = LONG POINTER TO FileSystemObject;
  FileSystemObject: TYPE = RECORD [dummy: UNSPECIFIED];
  VirtualFilename: TYPE = POINTER TO VirtualFilenameObject;
  VirtualFilenameObject: TYPE = RECORD [device, directory, name, version: STRING];
  Status: TYPE = {primary, secondary};
  Intent: TYPE = {enumeration, retrieval, deletion, renaming, unspecified};
  EnumerateFilesIntent: TYPE = Intent [enumeration..deletion];
  DumpFileIntent: TYPE = Intent [enumeration..retrieval];
  FileInfo: TYPE = POINTER TO FileInfoObject;
  FileInfoObject: TYPE = RECORD [
    fileType: FileType,
    byteSize: CARDINAL,
    byteCount: LONG CARDINAL,
    creationDate, writeDate, readDate, author: STRING];
  FileType: TYPE = {text, binary, unknown};
  ConcreteFileType: TYPE = FileType [text..binary];
  Mode: TYPE = {read, write, append, writeThenRead, readThenWrite};
  FileHandle: TYPE = LONG POINTER TO FileHandleObject;
  FileHandleObject: TYPE = RECORD [dummy: UNSPECIFIED];

  -- file primitives
  FilePrimitives: TYPE = POINTER TO FilePrimitivesObject;
  FilePrimitivesObject: TYPE = RECORD [
    CreateFileSystem: PROCEDURE [bufferSize: CARDINAL]
      RETURNS [fileSystem: FileSystem],
    DestroyFileSystem: PROCEDURE [fileSystem: FileSystem],
    DecomposeFilename, ComposeFilename: PROCEDURE [
      fileSystem: FileSystem, absoluteFilename: STRING,
      virtualFilename: VirtualFilename],
    InspectCredentials: PROCEDURE [
      fileSystem: FileSystem, status: Status, user, password: STRING],
    EnumerateFiles: PROCEDURE [
      fileSystem: FileSystem, files: STRING, intent: EnumerateFilesIntent,
      processFile: PROCEDURE [UNSPECIFIED, STRING, FileInfo],
      processFileData: UNSPECIFIED],
    OpenFile: PROCEDURE [
      fileSystem: FileSystem, file: STRING, mode: Mode, fileTypePlease: BOOLEAN,
      info: FileInfo] RETURNS [fileHandle: FileHandle, fileType: FileType],
    ReadFile: PROCEDURE [
      fileSystem: FileSystem, fileHandle: FileHandle,
      sendBlock: PROCEDURE [LONG UNSPECIFIED, LONG POINTER, CARDINAL],
      sendBlockData: LONG UNSPECIFIED],
    WriteFile: PROCEDURE [
      fileSystem: FileSystem, fileHandle: FileHandle,
      receiveBlock: PROCEDURE [LONG UNSPECIFIED, LONG POINTER, CARDINAL] RETURNS [CARDINAL],
      receiveBlockData: LONG UNSPECIFIED],
    CloseFile: PROCEDURE [
      fileSystem: FileSystem, fileHandle: FileHandle, aborted: BOOLEAN],
    DeleteFile: PROCEDURE [fileSystem: FileSystem, file: STRING],
    RenameFile: PROCEDURE [fileSystem: FileSystem, currentFile, newFile: STRING]];

  -- file system
  PilotFilePrimitives, SomeFilePrimitives, AltoFilePrimitives: PROCEDURE
    RETURNS [filePrimitives: FilePrimitives];

  -- **********************!  Mail System  !***********************

  -- mail types
  MailSystem: TYPE = POINTER TO MailSystemObject;
  MailSystemObject: TYPE = RECORD [dummy: UNSPECIFIED];
  Mailbox: TYPE = POINTER TO MailboxObject;
  MailboxObject: TYPE = RECORD [
    number: CARDINAL,
    mailbox, location: STRING,
    located, delivered: BOOLEAN,
    nextMailbox: Mailbox];
  MessageInfo: TYPE = POINTER TO MessageInfoObject;
  MessageInfoObject: TYPE = RECORD [
    byteCount: LONG CARDINAL, deliveryDate: STRING, opened, deleted: BOOLEAN];

  -- mail primitives
  MailPrimitives: TYPE = POINTER TO MailPrimitivesObject;
  MailPrimitivesObject: TYPE = RECORD [
    CreateMailSystem: PROCEDURE [
      filePrimitives: FilePrimitives, bufferSize: CARDINAL]
      RETURNS [mailSystem: MailSystem, forwardingProvided: BOOLEAN],
    DestroyMailSystem: PROCEDURE [mailSystem: MailSystem],
    InspectCredentials: PROCEDURE [
      mailSystem: MailSystem, status: Status, user, password: STRING],
    LocateMailboxes: PROCEDURE [
      mailSystem: MailSystem, localMailboxList: Mailbox],
    StageMessage: PROCEDURE [
      mailSystem: MailSystem,
      receiveBlock: PROCEDURE [LONG UNSPECIFIED, LONG POINTER, CARDINAL] RETURNS [CARDINAL],
      receiveBlockData: LONG UNSPECIFIED],
    DeliverMessage: PROCEDURE [mailSystem: MailSystem, localMailboxList: Mailbox],
    ForwardMessage: PROCEDURE [
      mailSystem: MailSystem, remoteMailboxList: Mailbox],
    RetrieveMessages: PROCEDURE [
      mailSystem: MailSystem, localMailbox: Mailbox,
      processMessage: PROCEDURE [MessageInfo],
      sendBlock: PROCEDURE [LONG UNSPECIFIED, LONG POINTER, CARDINAL],
      sendBlockData: LONG UNSPECIFIED]];

  -- mail systems
  SysMailPrimitives, SomeMailPrimitives: PROCEDURE
    RETURNS [mailPrimitives: MailPrimitives];

  -- **********************!  Communication System  !***********************

  -- communication types
  CommunicationSystem: TYPE = POINTER TO CommunicationSystemObject;
  CommunicationSystemObject: TYPE = RECORD [dummy: UNSPECIFIED];
  Connection: TYPE = POINTER TO ConnectionObject;
  ConnectionObject: TYPE = RECORD [dummy: UNSPECIFIED];
  Port: TYPE = POINTER TO PortObject;
  PortObject: TYPE = RECORD [dummy: UNSPECIFIED];
  BytePointer: TYPE = POINTER TO BytePointerObject;
  BytePointerObject: TYPE = RECORD [
    address: LONG POINTER, offset: BOOLEAN, count: CARDINAL];
  Byte: TYPE = [0..377B];

  -- communication primitives
  CommunicationPrimitives: TYPE = POINTER TO CommunicationPrimitivesObject;
  CommunicationPrimitivesObject: TYPE = RECORD [
    CreateCommunicationSystem: PROCEDURE
      RETURNS [communicationSystem: CommunicationSystem],
    DestroyCommunicationSystem: PROCEDURE [
      communicationSystem: CommunicationSystem],
    OpenConnection: PROCEDURE [
      communicationSystem: CommunicationSystem, remoteHost: STRING,
      remoteSocket: LONG CARDINAL, receiveSeconds: CARDINAL]
      RETURNS [connection: Connection],
    CloseConnection: PROCEDURE [
      communicationSystem: CommunicationSystem, connection: Connection],
    AbortConnection: PROCEDURE [
      communicationSystem: CommunicationSystem, connection: Connection,
      text: STRING],
    ActivatePort: PROCEDURE [
      communicationSystem: CommunicationSystem, localSocket: LONG CARDINAL,
      serviceConnection: PROCEDURE [UNSPECIFIED, Connection, STRING],
      serviceConnectionData: UNSPECIFIED, receiveSeconds: CARDINAL,
      filter: PROCEDURE [STRING, Purpose], purpose: Purpose] RETURNS [port: Port],
    DeactivatePort: PROCEDURE [
      communicationSystem: CommunicationSystem, port: Port],
    SendBytes: PROCEDURE [
      communicationSystem: CommunicationSystem, connection: Connection,
      bytePointer: BytePointer],
    ReceiveBytes: PROCEDURE [
      communicationSystem: CommunicationSystem, connection: Connection,
      bytePointer: BytePointer, settleForLess: BOOLEAN],
    SendByte: PROCEDURE [
      communicationSystem: CommunicationSystem, connection: Connection,
      byte: Byte],
    ReceiveByte: PROCEDURE [
      communicationSystem: CommunicationSystem, connection: Connection,
      settleForNone: BOOLEAN] RETURNS [byte: Byte, settledForNone: BOOLEAN],
    ProduceDiscontinuity, ConsumeDiscontinuity, ForceOutput: PROCEDURE [
      communicationSystem: CommunicationSystem, connection: Connection]];

  -- communication system
  OISCommunicationPrimitives, PupCommunicationPrimitives: PROCEDURE
    RETURNS [communicationPrimitives: CommunicationPrimitives];

  -- **********************!  Signals  !***********************

  -- error
  FTPError: SIGNAL [ftpError: FtpError, message: STRING];

  -- Note:  To add a new error:
  --   1) Add corresponding message to FTPAccessories.VerbalizeFtpError.
  --   2) Modify error categories below as necessary.
  --   3) Modify FTPProtocol.SignalToCode and CodeToSignal as necessary.

  -- error codes
  FtpError: TYPE = {
    -- communication errors
    noSuchHost, connectionTimedOut, connectionRejected, connectionClosed,
    noRouteToNetwork, connectionAbortedLocally, noNameLookupResponse,
    -- credential errors
    credentialsMissing, noSuchPrimaryUser, noSuchSecondaryUser,
    incorrectPrimaryPassword, incorrectSecondaryPassword, requestedAccessDenied,
    -- file errors
    illegalFilename, noSuchFile, fileAlreadyExists, fileBusy, noRoomForFile,
    fileDataError,
    -- dump errors
    errorBlockInDumpFile, unrecognizedDumpFileBlock, dumpFileBlockTooLong,
    dumpFileCheckSumInError,
    -- mail errors
    noValidRecipients, noSuchMailbox,
    -- client errors
    filePrimitivesNotSpecified, mailPrimitivesNotSpecified,
    communicationPrimitivesNotSpecified, filesModuleNotLoaded,
    mailModuleNotLoaded, noConnectionEstablished, connectionAlreadyEstablished,
    connectionNotOpenedForFiles, connectionNotOpenedForMail,
    illegalProcedureCallSequence, fileGroupDesignatorUnexpected,
    filenameUnexpected,
    -- protocol errors
    protocolVersionMismatch, functionNotImplemented, inputDiscontinuityUnexpected,
    outputDiscontinuityUnexpected, illegalProtocolSequence,
    protocolParameterListMissing, illegalProtocolParameterList,
    unrecognizedProtocolParameter, missingProtocolParameter,
    duplicateProtocolParameter, illegalBooleanParameter, illegalFileAttribute,
    illegalFileType, unrecognizedProtocolErrorCode, noSuchRecipientNumber,
    duplicateMailboxException, unrecognizedMailboxExceptionErrorCode,
    missingMessageLength, messageLongerThanAdvertised,
    messageShorterThanAdvertised,
    -- internal errors,
    stringTooLong, queueInconsistent, unexpectedEndOfFile,
    -- unidentified errors
    unidentifiedTransientError, unidentifiedPermanentError, unidentifiedError,
    -- pseudo error (meaning none)
    ok};

  -- error categories
  CommunicationError: TYPE = FtpError [noSuchHost..noNameLookupResponse];
  CredentialError: TYPE = FtpError [credentialsMissing..requestedAccessDenied];
  FileError: TYPE = FtpError [illegalFilename..fileDataError];
  DumpError: TYPE = FtpError [errorBlockInDumpFile..dumpFileCheckSumInError];
  MailError: TYPE = FtpError [noValidRecipients..noSuchMailbox];
  ClientError: TYPE = FtpError [filePrimitivesNotSpecified..filenameUnexpected];
  ProtocolError: TYPE = FtpError
    [protocolVersionMismatch..messageShorterThanAdvertised];
  InternalError: TYPE = FtpError [stringTooLong..unexpectedEndOfFile];
  UnidentifiedError: TYPE = FtpError
    [unidentifiedTransientError..unidentifiedError];

  -- private error categories
  UndefinedFunctionError: PRIVATE TYPE = FtpError
    [protocolVersionMismatch..functionNotImplemented];
  ProtocolSequenceError: PRIVATE TYPE = FtpError
    [inputDiscontinuityUnexpected..illegalProtocolSequence];
  IllegalParameterListError: PRIVATE TYPE = FtpError
    [protocolParameterListMissing..illegalFileAttribute];

  -- **********************!  Common Procedures  !***********************

  -- program primitives
  FTPInitialize, FTPFinalize: PROCEDURE;

  -- parameter primitives
  FTPSetBufferSize: PROCEDURE [pages: CARDINAL];
  FTPCatchUnidentifiedErrors: PROCEDURE [setting: BOOLEAN];

  -- **********************!  User (Common) Procedures  !***********************

  -- program primitives
  FTPCreateUser: PROCEDURE [
    filePrimitives: FilePrimitives,
    communicationPrimitives: CommunicationPrimitives] RETURNS [ftpuser: FTPUser];
  FTPDestroyUser: PROCEDURE [ftpuser: FTPUser];
  FTPAbortUser: PROCEDURE [ftpuser: FTPUser];

  -- connection primitives
  FTPSetContactSocket: PROCEDURE [
    ftpuser: FTPUser, socket: LONG CARDINAL, purpose: Purpose];
  FTPOpenConnection: PROCEDURE [
    ftpuser: FTPUser, host: STRING, purpose: Purpose, remoteInsignia: STRING];
  FTPRenewConnection, FTPCloseConnection: PROCEDURE [ftpuser: FTPUser];

  -- trace primitives
  FTPEnableTrace: PROCEDURE [ftpuser: FTPUser, writeString: PROCEDURE [STRING]];
  FTPDisableTrace: PROCEDURE [ftpuser: FTPUser];

  -- access primitive
  FTPSetCredentials: PROCEDURE [
    ftpuser: FTPUser, status: Status, user, password: STRING];

  -- **********************!  User (Files) Procedures  !***********************

  -- file enumeration primitive
  FTPEnumerateFiles: PROCEDURE [
    ftpuser: FTPUser, remoteFiles: STRING, intent: Intent,
    processFile: PROCEDURE [UNSPECIFIED, STRING, VirtualFilename, FileInfo],
    processFileData: UNSPECIFIED];

  -- file manipulation primitives
  FTPStoreFile, FTPRetrieveFile: PROCEDURE [
    ftpuser: FTPUser, localFile, remoteFile: STRING, fileType: FileType]
    RETURNS [byteCount: LONG CARDINAL];
  FTPTransferFile: PROCEDURE [
    srcFtpuser: FTPUser, srcFile: STRING, dstFtpuser: FTPUser, dstFile: STRING,
    fileType: FileType, transferFile: POINTER TO TransferFile,
    transferFileData: UNSPECIFIED] RETURNS [byteCount: LONG CARDINAL];

  TransferFile: TYPE = PROCEDURE [
    transferFileData: UNSPECIFIED,
    receiveBlock: PROCEDURE [UNSPECIFIED, POINTER, CARDINAL] RETURNS [CARDINAL],
    receiveBlockData: UNSPECIFIED,
    sendBlock: PROCEDURE [UNSPECIFIED, POINTER, CARDINAL],
    sendBlockData: UNSPECIFIED];

  FTPDeleteFile: PROCEDURE [ftpuser: FTPUser, remoteFile: STRING];
  FTPRenameFile: PROCEDURE [ftpuser: FTPUser, currentFile, newFile: STRING];

  -- filename primitives
  FTPSetFilenameDefaults: PROCEDURE [
    ftpuser: FTPUser, status: Status, virtualFilename: VirtualFilename];
  FTPNoteFilenameUsed: PROCEDURE [
    ftpuser: FTPUser, absoluteFilename: STRING, virtualFilename: VirtualFilename];

  -- **********************!  User (Dump) Procedures  !***********************

  FTPInventoryDumpFile: PROCEDURE [
    ftpuser: FTPUser, remoteDumpFile: STRING, intent: DumpFileIntent,
    processFile: PROCEDURE [UNSPECIFIED, STRING, VirtualFilename, FileInfo],
    processFileData: UNSPECIFIED];
  FTPBeginDumpFile: PROCEDURE [ftpuser: FTPUser, remoteDumpFile: STRING];
  FTPEndDumpFile: PROCEDURE [ftpuser: FTPUser];

  -- **********************!  User (Mail) Procedures  !***********************

  -- delivery primitives
  FTPBeginDeliveryOfMessage: PROCEDURE [ftpuser: FTPUser];
  FTPSendRecipientOfMessage: PROCEDURE [
    ftpuser: FTPUser, mailboxName: STRING,
    -- mailboxHostName and dmsName are going away soon
    mailboxHostName: STRING ← NIL, dmsName: STRING ← NIL];
  FTPIdentifyNextRejectedRecipient: PROCEDURE [
    ftpuser: FTPUser, errorMessage: STRING]
    RETURNS [recipientNumber: CARDINAL, recipientError: RecipientError];

  RecipientError: TYPE = {
    noSuchMailbox, noForwardingProvided, unspecifiedTransientError,
    unspecifiedPermanentError, unspecifiedError};

  FTPSendBlockOfMessage: PROCEDURE [
    ftpuser: FTPUser, source: POINTER, byteCount: CARDINAL];
  FTPEndDeliveryOfMessage: PROCEDURE [ftpuser: FTPUser];

  -- retrieval primitives
  FTPBeginRetrievalOfMessages: PROCEDURE [ftpuser: FTPUser, mailboxName: STRING];
  FTPIdentifyNextMessage: PROCEDURE [ftpuser: FTPUser, messageInfo: MessageInfo];
  FTPRetrieveBlockOfMessage: PROCEDURE [
    ftpuser: FTPUser, destination: POINTER, maxWordCount: CARDINAL]
    RETURNS [actualByteCount: CARDINAL];
  FTPEndRetrievalOfMessages: PROCEDURE [ftpuser: FTPUser];

  -- **********************!  Server (Common) Procedures  !***********************

  FTPCreateListener: PROCEDURE [
    purpose: Purpose, filePrimitives: FilePrimitives,
    mailPrimitives: MailPrimitives,
    communicationPrimitives: CommunicationPrimitives,
    backstopServer: POINTER TO BackstopServer, backstopServerData: UNSPECIFIED,
    filter: PROCEDURE [STRING, Purpose] ← RejectNothing]
    RETURNS [ftplistener: FTPListener];
  RejectNothing: PROCEDURE [STRING, Purpose];
  RejectThisConnection: ERROR [error: STRING];

  Purpose: TYPE = {files, mail, filesAndMail};
  SingularPurpose: TYPE = Purpose [files..mail];
  BackstopServer: TYPE = PROCEDURE [
    backstopServerData: UNSPECIFIED, purpose: SingularPurpose,
    originOfRequest, localInsignia: STRING, server: PROCEDURE];

  FTPDestroyListener: PROCEDURE [ftplistener: FTPListener, abortServers: BOOLEAN];

  -- **********************!  Externally Visible Objects  !***********************

  -- Note:  The client manipulates the object handles
  --   but not the objects themselves.

  -- user state information
  FTPUser: TYPE = POINTER TO FTPUserObject;
  FTPUserObject: PRIVATE TYPE = RECORD [
    filePrimitives: FilePrimitives,
    fileSystem: FileSystem,
    communicationPrimitives: CommunicationPrimitives,
    communicationSystem: CommunicationSystem,
    remoteFtpSocket, remoteMtpSocket: LONG CARDINAL,
    ftper, mtper: FTPer,
    propertyList, primaryPropertyList, secondaryPropertyList: PropertyList,
    purpose: Purpose,
    state: UserState,
    intent: Intent,
    nextBlockType: Byte,
    numberOfRecipients, numberOfValidRecipients: CARDINAL,
    numberOfBytesExpected, numberOfBytesReceived: LONG CARDINAL];

  UserState: PRIVATE TYPE = {
    unconnected, connected, enumeratingFiles, inventoryingDumpFile,
    dumpFileBeingSent, messageRecipientsBeingSent,
    initialMailboxExceptionsBeingReceived, messageTextBeingSent,
    finalMailboxExceptionsBeingReceived, messageDelivered, messageHeaderPending,
    messageTextPending, mailboxExhausted};

  -- listener state information
  FTPListener: TYPE = POINTER TO FTPListenerObject;
  FTPListenerObject: PRIVATE TYPE = RECORD [
    filePrimitives: FilePrimitives,
    mailPrimitives: MailPrimitives,
    communicationPrimitives: CommunicationPrimitives,
    communicationSystem: CommunicationSystem,
    backstopServer: BackstopServer,
    backstopServerData: UNSPECIFIED,
    ftpCharterObject, mtpCharterObject: CharterObject,
    ftpPort, mtpPort: Port,
    serverQueueObject: QueueObject];

  -- **********************!  Externally Invisible Objects  !***********************

  -- Note: These objects are declared here because they or their handles
  --   appear in the externally visible objects declared above.

  -- connection state information
  FTPer: PRIVATE TYPE = LONG POINTER TO FTPerObject;
  FTPerObject: PRIVATE TYPE = RECORD [
    communicationPrimitives: CommunicationPrimitives,
    communicationSystem: CommunicationSystem,
    connection: Connection,
    totalByteCount: LONG CARDINAL,
    inputString, outputString: STRING,
    tracing: BOOLEAN,
    writeString: PROCEDURE [STRING],
    directionOfLastTrace: TraceDirection];

  TraceDirection: PRIVATE TYPE = {in, out};

  -- property list
  PropertyList: PRIVATE TYPE = DESCRIPTOR FOR ARRAY Property OF STRING;
  PropertyListObject: PRIVATE TYPE = ARRAY Property OF STRING;

  Property: PRIVATE TYPE = {
    userName, userPassword, connectName, connectPassword, directory,
    serverFilename, device, nameBody, version, type, endOfLineConvention,
    byteSize, size, creationDate, writeDate, readDate, author, userAccount,
    mailbox, sender, length, dateReceived, opened, deleted};
  FileProperty: PRIVATE TYPE = Property [directory..author];

  -- server charter
  Charter: PRIVATE TYPE = POINTER TO CharterObject;
  CharterObject: PRIVATE TYPE = RECORD [
    ftplistener: FTPListener, purpose: SingularPurpose];

  -- queue and queue element
  Queue: PRIVATE TYPE = POINTER TO QueueObject;
  QueueObject: PRIVATE TYPE = MONITORED RECORD [
    head, tail: Element,
    elementCount: CARDINAL,
    identifiersCoincide: IdentifiersCoincide,
    elementDequeued, elementUnlocked: CONDITION];

  IdentifiersCoincide: PRIVATE TYPE = PROCEDURE [UNSPECIFIED, UNSPECIFIED]
    RETURNS [BOOLEAN];

  Element: PRIVATE TYPE = POINTER TO ElementObject;
  ElementObject: PRIVATE TYPE = RECORD [
    previous, next: Element,
    identifier: UNSPECIFIED,
    allocated, locked, exclusive: BOOLEAN];

  END. -- of FTPDefs