?? RIGHT := 110 ??
?? NEWTITLE := 'NFM$BTF_SERVER' ??
MODULE nfm$btf_server;

{}
{  PURPOSE:  This module contains procedures to perform the function of the
{            Batch Transfer Facility Server on NOS/VE (BTFS/VE).
{
{  DESCRIPTION:
{            The function of BTFS is performed by two entities:
{
{            1) The BOOT system task, which receives all incoming connections.
{               This BOOT task then executes a task to service each connection:
{
{            2) The SERVICE task, which receives a file from CDCNET via the
{               B101 A-A protocol.
{               The received file is then placed in a NOS/VE queue.
{}

?? NEWTITLE := 'Global Declarations Referenced', EJECT ??

*copyc amp$return
*copyc clp$convert_string_to_integer
*copyc clp$log_comment
*copyc clp$scan_parameter_list
*copyc clp$scan_token
*copyc fsp$open_file
*copyc jmp$submit_job
*copyc nap$attach_server_application
*copyc nap$detach_server_application
*copyc nap$get_attributes
*copyc nap$parse_accounting_data
*copyc nfp$dispose_user_msg_to_log
*copyc nfp$enqueue_status_directive
*copyc nfp$enqueue_task
*copyc nfp$format_message_to_job_log
*copyc nfp$get_server_asynch_event
*copyc nfp$initialize_control_block
*copyc nfp$ntf_receive_file
*copyc nfp$receive_command
*copyc nfp$receive_file
*copyc nfp$send_command
*copyc nfp$set_abnormal_if_normal
*copyc nfp$terminate_path
*copyc osp$format_message
*copyc osp$set_status_abnormal
*copyc osp$set_status_from_condition
*copyc pmp$compute_time_dif_in_seconds
*copyc pmp$continue_to_cause
*copyc pmp$disestablish_cond_handler
*copyc pmp$establish_condition_handler
*copyc pmp$execute
*copyc pmp$get_compact_date_time
*copyc pmp$get_program_description
*copyc pmp$get_program_size
*copyc pmp$get_unique_name
*copyc pmp$log

?? PUSH (LISTEXT := ON) ??

*copyc jmt$job_submission_options
*copyc nfc$command_definitions
*copyc nfc$parameter_definitions
*copyc nfc$parameter_00_definitions
*copyc nfc$parameter_03_definitions
*copyc nfc$parameter_04_definitions
*copyc nfc$parameter_08_definitions
*copyc nfc$parameter_09_definitions
*copyc nfc$parameter_12_definitions
*copyc nfc$parameter_13_definitions
*copyc nfc$parameter_16_definitions
*copyc nfc$parameter_17_definitions
*copyc nfc$parameter_20_definitions
*copyc nfc$parameter_22_definitions
*copyc nfc$parameter_25_definitions
*copyc nfc$parameter_26_definitions
*copyc nfc$parameter_30_definitions
*copyc nfc$parameter_31_definitions
*copyc nfc$parameter_32_definitions
*copyc nfc$parameter_58_definitions
*copyc nfe$batch_transfer_services
*copyc nft$batch_input_accounting_data
*copyc nft$command_set
*copyc nft$last_command_received
*copyc nft$last_command_sent
*copyc nft$parameter_set
*copyc nft$parameter_25_b101_text
*copyc nft$parameter_32_b101_text
*copyc nft$parameter_58_b101_text
*copyc nft$protocol_commands
*copyc nft$protocol_parameters
*copyc nft$transfer_modes
*copyc nfv$nam_application_names
*copyc osc$batch_transfer_server

?? POP ??

?? TITLE := 'Global Declarations Defined', EJECT ??

  TYPE
    batch_input_accounting = record
      CASE boolean OF
      = FALSE =
        data_string: jmt$job_input_device,
      = TRUE =
        size: 0 .. jmc$job_input_device_size,
        data_block: nft$batch_input_accounting_data,
      CASEND,
    recend,

    service_params = record
      network_file: ost$name,
      path_info: nft$network_connection,
    recend;


?? TITLE := '[XDCL] NFP$BTFS_BOOT', EJECT ??

  PROGRAM [XDCL] nfp$btfs_boot
    (VAR status: ost$status);

{}
{  PROCEDURE:  nfp$btfs_boot
{
{  PURPOSE:    The boot is a task which receives incoming BTFS connections
{              and initiates a service task to process each connection.
{
{  DESCRIPTION:
{              This routine is the starting procedure for the BTFS boot
{              task.  This task is responsible for receiving incoming BTFS
{              connections and executing a service task per connection.
{
{  INPUT PARAMETERS:
{              None
{
{  OUTPUT PARAMETERS:
{              status : status of the procedure
{
{  ALGORITHM:  Establish condition handler
{              Sign on as server to NAMVE
{              LOOP
{                Receive connect
{                If error, abort
{                Execute service task
{              LOOPEND
{}

?? NEWTITLE := '  BOOT_HANDLER', EJECT ??

    PROCEDURE boot_handler
      (    condition: pmt$condition;
           condition_desc: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR trap_status: ost$status);

{}
{  PROCEDURE:  boot_handler
{
{  PURPOSE:    This is the condition handler for nfm$btfs_boot.
{
{}

      VAR
        handler_ignore_status: ost$status,
        local_status: ost$status;

{}

      pmp$log ('BTFS boot task terminating', handler_ignore_status);

      { Break connection with BTF/DI }
      nfp$terminate_path (application, FALSE, path, handler_ignore_status);

      { Advise NAMVE that BTFS is gone }
      nap$detach_server_application (nfv$nam_application_names [application],
            handler_ignore_status);

      osp$set_status_from_condition (nfc$status_id, condition, save_area,
            local_status, handler_ignore_status);

      nfp$format_message_to_job_log (local_status);

{}

    PROCEND boot_handler;

?? OLDTITLE, EJECT ??

{}
{   NFP$BTFS_BOOT Data
{}

    VAR
      application: nft$application_values,
      conditions: pmt$condition,
      establish_descriptor: pmt$established_handler,
      lcn_boot: boolean,
      log_message: string (nfc$trace_commands_width),
      log_names: ARRAY [1..1] OF ost$name,
      log_status: ost$status,
      max_nam_connections: nat$number_of_connections,
      nam_boot: boolean,
      network_file_name: ost$name,
      number_of_libraries: pmt$number_of_libraries,
      number_of_modules: pmt$number_of_modules,
      number_of_objects: pmt$number_of_object_files,
      parameter_block: SEQ (REP 1 of service_params),
      parameter_pointer: ^service_params,
      parameter_set: service_params,
      path: nft$network_connection,
      program_attributes: ^pmt$program_attributes,
      program_description: ^pmt$program_description,
      program_parameters: ^pmt$program_parameters,
      task_id: pmt$task_id,
      task_id_string: string (10),
      task_id_string_length: integer,
      task_queue: nft$task_queue,
      task_status: pmt$task_status;

?? EJECT ??

{}
{   BEGIN nfp$btfs_boot
{}

    status.normal := TRUE;

{}
{   Establish condition handler
{}

    conditions.selector := pmc$condition_combination;
    conditions.combination := $pmt$condition_combination
          [pmc$system_conditions, mmc$segment_access_condition,
          pmc$block_exit_processing, pmc$user_defined_condition,
          ifc$interactive_condition];
    pmp$establish_condition_handler (conditions, ^boot_handler,
          ^establish_descriptor, status);
    IF NOT status.normal THEN
      nfp$format_message_to_job_log (status);
      RETURN; {----->
    IFEND;

{}
{   Initialize variables
{}

    application := nfc$application_btfs;
    lcn_boot := FALSE;
    nam_boot := TRUE;
    path.application_sequence_number := 1;
    path.path_connected := FALSE;
    ALLOCATE path.network_file: [STRLENGTH (network_file_name)];
    IF (path.network_file = NIL) THEN
      osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error,
            'BTFS nfp$btfs_boot - ALLOCATE -', status);
      nfp$format_message_to_job_log (status);
      RETURN; {----->
    IFEND;
    task_queue.head := NIL;
    task_queue.tail := NIL;
    task_queue.number_of_tasks := 0;

{}
{     Sign on as server to NAMVE
{}

    max_nam_connections := 0; {** Use all that are available **}
    nap$attach_server_application (nfv$nam_application_names [application],
          max_nam_connections, status);
    IF NOT status.normal THEN
      nfp$format_message_to_job_log (status);
      RETURN; {----->
    IFEND;

{}
{     Get program description for execute of service task.
{     Note that this BOOT task and executed SERVICE_TASK are loaded from the
{     same module,  so much of the program description data is the same.
{}

    pmp$get_program_size (number_of_objects, number_of_modules,
          number_of_libraries, status);
    IF NOT status.normal THEN
      nfp$format_message_to_job_log (status);
      RETURN; {----->
    IFEND;
    PUSH program_description: [[REP (#SIZE (pmt$program_attributes) +
          (number_of_objects * #SIZE (amt$local_file_name)) +
          (number_of_modules * #SIZE (pmt$program_name)) +
          (number_of_libraries * #SIZE (amt$local_file_name))) OF cell]];
    pmp$get_program_description (program_description^, status);
    IF NOT status.normal THEN
      nfp$format_message_to_job_log (status);
      RETURN; {----->
    IFEND;
    RESET program_description;
    NEXT program_attributes IN program_description;
    program_attributes^.contents := program_attributes^.contents +
          $pmt$prog_description_contents [pmc$starting_proc_specified];
    program_attributes^.starting_procedure := 'NFP$BTFS_SERVICE_TASK';

   log_names [1] := 'JOB_MESSAGE';
   clp$log_comment ('Batch Transfer Facility Server', log_names, log_status);

{}
{     MAIN loop
{}

  /process_connection/
    WHILE TRUE DO

{}
{     Get network path name
{}

      pmp$get_unique_name (network_file_name, status);
      IF NOT status.normal THEN
        nfp$format_message_to_job_log (status);
        RETURN; {----->
      IFEND;
      path.application_sequence_number := path.application_sequence_number + 1;
      path.network_file^ := network_file_name;

{}
{     Get network connection - this is where we wait for something to do
{     Upon normal exit from nfp$get_server_async_event we should have a
{     connection to BTF/DI
{}

      nfp$get_server_asynch_event (application, path, lcn_boot, nam_boot,
            task_queue, status);
      IF NOT status.normal THEN
        nfp$format_message_to_job_log (status);
        RETURN; {----->
      IFEND;

{}
{     Now we have a connection, execute the service task
{}

      parameter_set.path_info := path;
      parameter_set.network_file := path.network_file^;
      program_parameters := ^parameter_block;
      RESET program_parameters;
      NEXT parameter_pointer IN program_parameters;
      parameter_pointer^ := parameter_set;
      RESET program_parameters;

      pmp$execute (program_description^, program_parameters^, osc$nowait,
            task_id, task_status, status);
      IF status.normal THEN
        IF nfc$trace_commands THEN
          log_message := 'BTFS - Execute service task, task id = xxxxxxxxxx';
          STRINGREP (task_id_string, task_id_string_length, task_id);
          log_message (39, 10) := task_id_string (1, task_id_string_length);
          pmp$log (log_message, log_status);
          IF NOT log_status.normal THEN
            nfp$format_message_to_job_log (log_status);
            RETURN; {----->
          IFEND;
        IFEND;
        nfp$enqueue_task (task_id, path, task_queue);
        path.path_connected := FALSE;
      ELSE
        { Break connecton with BTF/DI }
        nfp$terminate_path (application, FALSE, path, status);
      IFEND;

    WHILEND /process_connection/;

{}

  PROCEND nfp$btfs_boot;

?? TITLE := '[XDCL] NFP$BTFS_SERVICE_TASK', EJECT ??

  PROCEDURE [XDCL] nfp$btfs_service_task
    (    parameter_list: clt$parameter_list);

{}
{  PROCEDURE:  nfp$btfs_service_task
{
{  PURPOSE:    This is the entry procedure for the BTFS service task.
{              This task is executed by the "BOOT".
{
{  DESCRIPTION:
{              This routine services a connection by transferring in a file
{              that is then placed in a NOS/VE queue.
{
{  INPUT PARAMETERS:
{              parameter_list : Passed via PMP$EXECUTE, contains network_file &
{                               network path, needed for the control_block.
{
{  OUTPUT PARAMETERS:
{              none
{
{  ALGORITHM:
{              Get connection info
{              Establish connect
{              Transfer file
{}

?? NEWTITLE := '  NFP$BTF_SERVICE_TASK Data', EJECT ??

    VAR
      parameter_00_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p00_min_size, nfc$p00_max_size,
            [nfc$rft, nfc$rpos, nfc$rneg], [], [], [], FALSE]];

    VAR
      parameter_01_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_02_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_03_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p03_min_size, nfc$p03_max_size, [nfc$rft], [],
            [], [], FALSE]];

    VAR
      parameter_04_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p04_min_param_len, nfc$p04_max_param_len,
            [nfc$rneg, nfc$stop, nfc$stopr], [], [], [], FALSE]];

    VAR
      parameter_05_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_06_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_07_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_08_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p08_min_param_len,
            nfc$p08_max_param_len_b101, [], [], [], [], TRUE]];

    VAR
      parameter_09_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p09_min_param_len,
            nfc$p09_max_param_len_b101, [], [], [], [], TRUE]];

    VAR
      parameter_10_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_11_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_12_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p12_min_size_b101, nfc$p12_max_size_b101, [],
            [], [], [], FALSE]];

    VAR
      parameter_13_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p13_min_param_size, nfc$p13_max_param_size,
            [], [], [], [], FALSE]];

    VAR
      parameter_16_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p16_min_param_length,
            nfc$p16_max_param_length_b101, [], [], [], [], FALSE]];

    VAR
      parameter_17_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } TRUE, nfc$p17_min_size, nfc$p17_max_size, [],
            [], [], [], FALSE]];

    VAR
      parameter_18_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_19_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_20_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p20_min_size, nfc$p20_max_size, [nfc$rft], [],
            [], [], FALSE]];

    VAR
      parameter_21_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_22_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p22_min_size, nfc$p22_max_size,
            [nfc$rft, nfc$rpos], [], [], [], FALSE]];

    VAR
      parameter_23_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_24_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_25_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p25_min_param_size,
            nfc$p25_max_param_size_b101, [nfc$rft], [], [], [], FALSE]];

    VAR
      parameter_26_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p26_min_param_length,
            nfc$p26_max_param_length_b101, [], [], [], [], FALSE]];

    VAR
      parameter_27_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_28_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_29_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_30_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p30_min_param_size, nfc$p30_max_param_size,
            [], [], [], [], FALSE]];

    VAR
      parameter_31_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p31_min_param_length_b101,
            nfc$p31_max_param_length_b101, [], [], [], [], FALSE]];

    VAR
      parameter_32_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p32_min_param_length_b101,
            nfc$p32_max_param_length_b101, [nfc$rft], [], [], [], FALSE]];

    VAR
      parameter_33_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_51_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_52_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_53_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_54_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_55_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_56_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_57_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_58_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE],
            [{ B101: } TRUE, nfc$p58_min_param_size, nfc$p58_max_param_size,
            [nfc$rft], [], [], [], FALSE]];

    VAR
      parameter_59_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_60_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_90_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_91_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_92_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_93_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_94_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_95_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_96_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_97_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_98_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_99_rules: [READ, STATIC] nft$parameter_rules :=
            [[{ A102: } FALSE], [{ A101: } FALSE], [{ B101: } FALSE]];

    VAR
      parameter_rules: [READ, STATIC] nft$parameter_rules_array := [

            ^parameter_00_rules, ^parameter_01_rules, ^parameter_02_rules,
            ^parameter_03_rules, ^parameter_04_rules, ^parameter_05_rules,
            ^parameter_06_rules, ^parameter_07_rules, ^parameter_08_rules,
            ^parameter_09_rules, ^parameter_10_rules, ^parameter_11_rules,
            ^parameter_12_rules, ^parameter_13_rules, ^parameter_16_rules,
            ^parameter_17_rules, ^parameter_18_rules, ^parameter_19_rules,
            ^parameter_20_rules, ^parameter_21_rules, ^parameter_22_rules,
            ^parameter_23_rules, ^parameter_24_rules, ^parameter_25_rules,
            ^parameter_26_rules, ^parameter_27_rules, ^parameter_28_rules,
            ^parameter_29_rules, ^parameter_30_rules, ^parameter_31_rules,
            ^parameter_32_rules, ^parameter_33_rules, ^parameter_51_rules,
            ^parameter_52_rules, ^parameter_53_rules, ^parameter_54_rules,
            ^parameter_55_rules, ^parameter_56_rules, ^parameter_57_rules,
            ^parameter_58_rules, ^parameter_59_rules, ^parameter_60_rules,
            ^parameter_90_rules, ^parameter_91_rules, ^parameter_92_rules,
            ^parameter_93_rules, ^parameter_94_rules, ^parameter_95_rules,
            ^parameter_96_rules, ^parameter_97_rules, ^parameter_98_rules,
            ^parameter_99_rules];

?? EJECT ??

    VAR
      conditions: pmt$condition,
      control_block: nft$control_block,
      establish_descriptor: pmt$established_handler,
      ignore_status: ost$status,
      log_message: string (nfc$trace_commands_width),
      log_message_length: integer,
      log_status: ost$status,
      network_file_name: ost$name,
      parameter_sequence: ^clt$parameter_list,
      parameter_value: ^service_params,
      p17_param: nft$parameter_17_definition,
      p25_params: nft$p25_b101_params,
      p26_param: nft$parameter_26_definition,
      p32: nft$p32_b101_text,
      p32_ntf_params: nft$p32_b101_ntf_params,
      p32_private_params: nft$p32_b101_private_params,
      p32_public_params: nft$p32_b101_public_params,
      p58: nft$p58_b101_text,
      p58_ntf_params: nft$p58_b101_ntf_params,
      p58_private_params: nft$p58_b101_private_params,
      p58_public_params: nft$p58_b101_public_params,
      status: ost$status;

?? OLDTITLE ??
?? NEWTITLE := '  PROCESS_RFT', EJECT ??

    PROCEDURE process_rft
      (    received_params: nft$parameter_set;
       VAR control_block: nft$control_block;
       VAR process_rft_status: ost$status);

{}
{  PROCEDURE:  process_rft
{
{  PURPOSE:    This procedure unpacks parameters received on an RFT command.
{
{  DESCRIPTION:
{              The RFT command carries with it a series of mandatory and
{              optional parameters.  These parameters are:
{
{              - Parameter 17:  Disposition code (Optional)
{              - Parameter 25:  Transfer LID
{              - Parameter 26:  User job name (Optional)
{              - Parameter 32:  System routing text
{              - Parameter 58:  Output file destination
{
{  INPUT PARAMETERS:
{              received_params    : parameters received on RFT
{
{  OUTPUT PARAMETERS:
{              process_rft_status : status of procedure
{
{  INPUT/OUTPUT PARAMETER:
{              control_block      : used for communicating with various nfp$...
{                                   helper procedures
{
{  ALGORITHM:
{              Get value of file disposition from parameter 17
{              Get value of destination family from parameter 25
{              Get value of user job name from parameter 26
{              Call unpack_text to get values of parameter 32
{              Call unpack_text to get values of parameter 58
{}

?? NEWTITLE := '    UNPACK_TEXT', EJECT ??

      PROCEDURE unpack_text
        (    parameter: string ( * );
             text: string ( * );
         VAR param_array: array [1 .. * ] of ost$name;
         VAR unpack_text_status: ost$status);

{}
{  PROCEDURE:  unpack_text
{
{  PURPOSE:    This procedure unpacks names contained in a text-type protocol
{              parameter.
{
{  DESCRIPTION:
{              Text-type protocol parameters (for example parameter 32)
{              contain a variant identifier (eg CN0) followed by a comma
{              and a list of names separated by commas.  This procedure returns
{              each of these names in an element of the passed param_array.
{
{              An unexpected number of parameters, or a non-name parameter
{              will be considered a protocol violation.
{
{  INPUT PARAMETERS:
{              parameter   : A string indicating what protocol parameter is
{                            being processed - used in error messages
{              text        : The text from the protocol parameter, excluding
{                            the variant identifier
{
{  OUTPUT PARAMETERS:
{              param_array : Each element in this array will contiain a name
{                            as obtained from the input text
{              status      : Status of procedure
{
{  ALGORITHM:  clt$scan_token is used to crack the text - only commas are
{              allowed as separators
{}

        VAR
          errmsg: string (80),
          first_token: boolean,
          length: integer,
          param_index: integer,
          token_index: ost$string_index,
          token: clt$token;

{}

      /initialize_param_array/
        FOR param_index := LOWERBOUND (param_array)
              TO UPPERBOUND (param_array) DO
          param_array [param_index] := osc$null_name;
        FOREND /initialize_param_array/;

        first_token := TRUE;
        param_index := LOWERBOUND (param_array);
        token.kind := clc$unknown_token;
        token_index := 1;

{}
{     Main loop
{}

      /process_tokens/
        WHILE NOT (token.kind = clc$eol_token) DO
          clp$scan_token (text, token_index, token, unpack_text_status);
          IF NOT unpack_text_status.normal THEN
            nfp$format_message_to_job_log (unpack_text_status);
            RETURN; {----->
          IFEND;

          CASE token.kind OF
          = clc$name_token =
            param_array [param_index] := token.name.value (1, token.name.size);
          = clc$comma_token =
            IF (param_index = UPPERBOUND (param_array)) THEN
              STRINGREP (errmsg, length, 'BTFS unpack_text: (', parameter,
                    ') too many values -');
              osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error,
                    errmsg (1, length), unpack_text_status);
              RETURN; {----->
            ELSEIF NOT first_token THEN
              param_index := SUCC (param_index);
            IFEND;
          = clc$eol_token =
            IF (param_index <> UPPERBOUND (param_array)) THEN
              STRINGREP (errmsg, length, 'BTFS unpack_text: (', parameter,
                    ') too few values -');
              osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error,
                    errmsg (1, length), unpack_text_status);
              RETURN; {----->
            IFEND;
          ELSE
            STRINGREP (errmsg, length, 'BTFS unpack_text: (', parameter,
                  ') bad token -');
            osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error,
                  errmsg (1, length), unpack_text_status);
            RETURN; {----->
          CASEND;

          first_token := FALSE;

        WHILEND /process_tokens/;

{}

      PROCEND unpack_text;

?? OLDTITLE, EJECT ??

      VAR
        errmsg: string (80),
        length: integer;

{}
{     Process parameter 17 (disposition code - optional)
{}

      IF nfc$file_disposition IN received_params THEN
        p17_param := control_block.disposition_code;
      IFEND;

{}
{     Process parameter 25 (transfer lid - becomes execution family)
{}

      unpack_text ('P25', control_block.remote_lid, p25_params,
            process_rft_status);
      IF NOT process_rft_status.normal THEN
        RETURN; {----->
      IFEND;

{}
{     Process parameter 26 (job name - optional)


      IF nfc$job_name IN received_params THEN
        p26_param := control_block.receive_job_name;
        IF p26_param.value(1, p26_param.size) = ' ' THEN
          p26_param.size := 0;
        IFEND;
      ELSE
        p26_param.size := 0;
      IFEND;

{}
{     Process parameter 32 (system routing text)
{}

      p32.variant := control_block.receive_systems_routing_text.
            parameters (1, nfc$p32_variant_size);
      p32.text := control_block.receive_systems_routing_text.
            parameters (nfc$p32_variant_size + 1,
            control_block.receive_systems_routing_text.size -
            nfc$p32_variant_size);

      IF (p32.variant = nfc$p32_b101_private_ios_id) THEN
        unpack_text ('P32', p32.text, p32_private_params, process_rft_status);
      ELSEIF (p32.variant = nfc$p32_b101_public_ios_id) THEN
        unpack_text ('P32', p32.text, p32_public_params, process_rft_status);
      ELSEIF (p32.variant = nfc$p32_b101_ntf_id) THEN
        unpack_text ('P32', p32.text, p32_ntf_params, process_rft_status);
      ELSE
        STRINGREP (errmsg, length, 'BTFS process_rft: (P32) unknown variant -',
              p32.variant, '-');
        osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error,
              errmsg (1, length), process_rft_status);
        RETURN; {----->
      IFEND;

      IF NOT process_rft_status.normal THEN
        RETURN; {----->
      IFEND;

{}
{     Process parameter 58 (output file destination)
{}

      p58.variant := control_block.default_output_file_destination.
            value (1, nfc$p58_variant_size);
      p58.text := control_block.default_output_file_destination.
            value (nfc$p58_variant_size + 1, control_block.
            default_output_file_destination.size - nfc$p58_variant_size);

      IF (p58.variant = nfc$p58_b101_private_ios_id) THEN
        unpack_text ('P58', p58.text, p58_private_params, process_rft_status);
      ELSEIF (p58.variant = nfc$p58_b101_public_ios_id) THEN
        unpack_text ('P58', p58.text, p58_public_params, process_rft_status);
      ELSEIF (p58.variant = nfc$p58_b101_ntf_id) THEN
        unpack_text ('P58', p58.text, p58_ntf_params, process_rft_status);
      ELSE
        STRINGREP (errmsg, length, 'BTFS process_rft: (P58) unknown variant -',
              p58.variant, '-');
        osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error,
              errmsg (1, length), process_rft_status);
        RETURN; {----->
      IFEND;

      IF NOT process_rft_status.normal THEN
        RETURN; {----->
      IFEND;

      process_rft_status.normal := TRUE;

    PROCEND process_rft;

?? OLDTITLE ??
?? NEWTITLE := '  SERVICE_HANDLER', EJECT ??

    PROCEDURE service_handler
      (    condition: pmt$condition;
           condition_desc: ^pmt$condition_information;
           save_area: ^ost$stack_frame_save_area;
       VAR trap_status: ost$status);

{}
{  PROCEDURE:  service_handler
{
{  PURPOSE:    This is the condition handler for nfm$btfs_service_task.
{
{}

      VAR
        handler_ignore_status: ost$status,
        local_status: ost$status;

{}

      { Break connection with BTF/DI }
      nfp$terminate_path (control_block.application, FALSE, control_block.path,
            handler_ignore_status);

      amp$return (control_block.file_name, handler_ignore_status);

      pmp$log ('BTFS service task terminating', handler_ignore_status);

      osp$set_status_from_condition (nfc$status_id, condition, save_area,
            local_status, handler_ignore_status);

      nfp$format_message_to_job_log (local_status);

{}

    PROCEND service_handler;

?? OLDTITLE ??
?? NEWTITLE := '  SUBMIT_JOB', EJECT ??

    PROCEDURE submit_job
      (    accounting_data: batch_input_accounting;
       VAR control_block: nft$control_block;
       VAR stopr_params: nft$parameter_set;
       VAR status: ost$status);

{}
{  PROCEDURE:  submit_job
{
{  PURPOSE:    This procedure submits the file received as a batch job
{
{  DESCRIPTION:
{              This procedure sets up the options required to properly set
{              up the job_attributes of the job to be submitted.
{              The job is then submitted to the input queue.
{              The parameters that will be returned on the STOPR are
{              determined by the success/failure of the submit_job.
{
{  INPUT PARAMETERS:
{              accounting_data : Data used for batch_input communication
{                                accounting.
{
{  OUTPUT PARAMETERS:
{              status          : Status of procedure
{              stopr_params    : Parameter set to be sent on STOPR command. Will
{                                be set depending on status of jmp$submit_job.
{
{  INPUT/OUTPUT PARAMETER:
{              control_block   : used for communicating with various nfp$...
{                                helper procedures
{
{  ALGORITHM:
{              Set up job submission options
{              Submit_job
{              IF success THEN
{                Set STOPR parameters for successful transfer
{              ELSE
{                Set STOPR parameters for unsuccessful transfer
{              IFEND
{
{}

      TYPE
        job_attributes = (control_family, control_user, destination_family,
              destination_usage, execution_family, inherit_job_attributes,
              job_input_device, output_destination, origin_application, station,
              station_operator, user_job_name);

      VAR
        attribute_index: job_attributes,
        enqueue_status: ost$status,
        index: 0 .. jmc$maximum_attribute_index,
        job_options: array [job_attributes] of boolean,
        number_of_attributes: integer,
        p08_list: nft$directive_entry_list_head,
        submit_options: ^jmt$job_submission_options,
        submit_status: ost$status,
        submit_sys_name: jmt$system_supplied_name,
        xfer_status: ost$status;

      index := 0;
      number_of_attributes := 0;
      p08_list.head := NIL;
      p08_list.tail := NIL;

{}
{     Set up job_submission_options
{}

    /initialize_job_options/
      FOR attribute_index := LOWERBOUND (job_options)
            TO UPPERBOUND (job_options) DO
        job_options [attribute_index] := FALSE;
      FOREND /initialize_job_options/;

      job_options [execution_family] := TRUE;
      number_of_attributes := number_of_attributes + 1;

      job_options [inherit_job_attributes] := TRUE;
      number_of_attributes := number_of_attributes + 1;

      job_options [job_input_device] := TRUE;
      number_of_attributes := number_of_attributes + 1;

      job_options [origin_application] := TRUE;
      number_of_attributes := number_of_attributes + 1;

      IF p26_param.size > 0 THEN
        job_options [user_job_name] := TRUE;
        number_of_attributes := number_of_attributes + 1;
      IFEND;

      IF (p32.variant = nfc$p32_b101_private_ios_id) THEN
        job_options [control_family] := TRUE;
        job_options [control_user] := TRUE;
        number_of_attributes := number_of_attributes + 2;
      IFEND;

      IF (p58.variant = nfc$p58_b101_private_ios_id) THEN
        job_options [destination_family] := TRUE;
        job_options [destination_usage] := TRUE;
        job_options [output_destination] := TRUE;
        job_options [station] := TRUE;
        job_options [station_operator] := TRUE;
        number_of_attributes := number_of_attributes + 5;
      ELSE
        job_options [destination_usage] := TRUE;
        job_options [output_destination] := TRUE;
        job_options [station] := TRUE;
        number_of_attributes := number_of_attributes + 3;
      IFEND;

      PUSH submit_options: [1 .. number_of_attributes];

{}
{     Process specified attributes
{}

    /process_specified_attributes/
      FOR attribute_index := LOWERBOUND (job_options)
            TO UPPERBOUND (job_options) DO

        IF job_options [attribute_index] THEN

          index := index + 1;

          CASE attribute_index OF

          = control_family =
            submit_options^ [index].key := jmc$control_family;
            submit_options^ [index].control_family :=
                  p32_private_params [nfc$p32_b101_op_family];

          = control_user =
           submit_options^ [index].key := jmc$control_user;
           submit_options^ [index].control_user :=
                  p32_private_params [nfc$p32_b101_op_user_name];

          = destination_family =
            IF p58_private_params [nfc$p58_b101_op_family] <> osc$null_name THEN
              submit_options^ [index].key := jmc$output_destination_family;
              submit_options^ [index].output_destination_family :=
                    p58_private_params [nfc$p58_b101_op_family];
            ELSE
              submit_options^ [index].key := jmc$null_attribute;
            IFEND;

          = destination_usage =
            submit_options^ [index].key := jmc$output_destination_usage;
            IF (p58.variant = nfc$p58_b101_private_ios_id) THEN
              submit_options^ [index].output_destination_usage :=
                    jmc$private_usage;
            ELSE
              submit_options^ [index].output_destination_usage :=
                    jmc$public_usage;
            IFEND;

          = execution_family =
            submit_options^ [index].key := jmc$default_login_family;
            submit_options^ [index].default_login_family :=
                  p25_params [nfc$p25_input_family];

          = inherit_job_attributes =

            submit_options^ [index].key := jmc$inherit_job_attributes;
            submit_options^ [index].inherit_job_attributes := FALSE;

          = job_input_device =
            submit_options^ [index].key := jmc$job_input_device;
            submit_options^ [index].job_input_device :=
                  ^accounting_data.data_string;

          = output_destination =
            submit_options^ [index].key := jmc$output_destination;
            IF (p58.variant = nfc$p58_b101_private_ios_id) THEN
              submit_options^ [index].output_destination :=
                    p58_private_params [nfc$p58_b101_control_facility];
            ELSE
              submit_options^ [index].output_destination :=
                    p58_public_params [nfc$p58_b101_station];
            IFEND;

          = origin_application =
            submit_options^ [index].key := jmc$origin_application_name;
            submit_options^ [index].origin_application_name :=
                  osc$batch_transfer_server;

          = station =
            submit_options^ [index].key := jmc$station;
            IF (p58.variant = nfc$p58_b101_private_ios_id) THEN
              submit_options^ [index].station :=
                    p58_private_params [nfc$p58_b101_control_facility];
            ELSE
              submit_options^ [index].station :=
                    p58_public_params [nfc$p58_b101_station];
            IFEND;

          = station_operator =
            submit_options^ [index].key := jmc$station_operator;
            submit_options^ [index].station_operator :=
                  p58_private_params [nfc$p58_b101_op_user_name];

          = user_job_name =
            submit_options^ [index].key := jmc$user_job_name;
            submit_options^ [index].user_job_name :=
                  p26_param.value(1, p26_param.size);

          ELSE

            osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error,
                  'BTFS submit_job - CASE states -', status);
            nfp$format_message_to_job_log (status);
            RETURN; {----->

          CASEND;
        IFEND;
      FOREND /process_specified_attributes/;

{}
{     Submit job to input queue
{}

      jmp$submit_job (control_block.file_name, submit_options, submit_sys_name,
            submit_status);

      IF submit_status.normal THEN
        control_block.send_file_name.value := submit_sys_name;
        control_block.send_file_name.size := jmc$system_supplied_name_size;
        stopr_params := $nft$parameter_set [nfc$state_of_transfer,
              nfc$file_name];
      ELSE
        { Set submit_status text into parameter 08 (user message) }
        nfp$enqueue_status_directive (submit_status, p08_list, status);
        IF NOT status.normal THEN
          nfp$format_message_to_job_log (status);
          RETURN; {----->
        IFEND;
        control_block.send_user_messages := p08_list.head;
        osp$set_status_abnormal (nfc$status_id, nfe$transfer_rejected_message,
              '', xfer_status);
        nfp$set_abnormal_if_normal (xfer_status,
              control_block.state_of_transfer);
        stopr_params := $nft$parameter_set [nfc$state_of_transfer,
              nfc$user_message];
      IFEND;

{}

    PROCEND submit_job;

?? OLDTITLE ??
?? NEWTITLE := '  TRANSFER_FILE', EJECT ??

    PROCEDURE transfer_file
      (VAR control_block: nft$control_block);

{}
{  PROCEDURE:  transfer_file
{
{  PURPOSE:    This procedure gets a file from the BTF/DI peer application.
{
{  DESCRIPTION:
{              This routine performs the protocol initialization and
{              termination necessary to transfer a file from BTF/DI.
{              The protocol employed is the A-A B101 protocol.  Actual
{              data transfer is performed by nfp$receive_file.
{
{              The file received will be placed in a NOS/VE queue.
{              This routine is capable of handling multiple back-to-back
{              file transfers, if needed.
{
{  INPUT PARAMETERS:
{              None
{
{  OUTPUT PARAMETERS:
{              None
{
{  INPUT/OUTPUT PARAMETER:
{              control_block : used for communicating with various nfp$...
{                              helper procedures
{
{  ALGORITHM:
{              The file transfer logic is modelled after the following state
{              table:

?? EJECT ??

{
{         FILE TRANSFER STATE TABLE
{         -------------------------
{
{
{
{                RFT     GO     STOP     ETP    FINI    ERROR
{
{             +-------+-------+-------+-------+-------+-------+
{             |  S/   |       |       |       |       |(Bad   |
{      START  | RPOS  |   *   |   *   |   *   |   *   |  RFT) |
{             |       |       |       |       |       |S/RNEG |
{             |>XFER  |       |       |       |       |>ERRSTP|
{             +-------+-------+-------+-------+-------+-------+
{             |       | Xfer  |  S/   |       |       |(Bad   |
{      XFER   |   *   | file  | STOPR |   *   |   *   | xfer) |
{             |       |       |       |       |       |       |
{             |       |>ENQF  |>WETP  |       |       |>ERRSTP|
{             +-------+-------+-------+-------+-------+-------+
{             |       |       |Enqueue|       |       |(Bad   |
{      ENQF   |   *   |   *   | file, |   *   |   *   | STOP) |
{             |       |       |S/STOPR|       |       |S/STOPR|
{             |       |       |>WETP  |       |       |>WETP  |
{             +-------+-------+-------+-------+-------+-------+
{             |       |       |  S/   |       |       |       |
{      ERRSTP |   *   |   *   | STOPR |   *   |   *   |   *   |
{             |       |       |       |       |       |       |
{             |       |       |>WETP  |       |       |       |
{             +-------+-------+-------+-------+-------+-------+
{             |  S/   |       |       |  S/   |       |(Bad   |
{      WETP   | RPOS  |   *   |   *   | ETPR  |   *   |  RFT) |
{             |       |       |       |       |       |S/RNEG |
{             |>XFER  |       |       |>WFINI |       |>ERRSTP|
{             +-------+-------+-------+-------+-------+-------+
{             |       |       |       |       |       |       |
{      WFINI  |   *   |   *   |   *   |   *   | Exit  |   *   |
{             |       |       |       |       |       |       |
{             |       |       |       |       |       |       |
{             +-------+-------+-------+-------+-------+-------+
{
{            S/  Send Command
{            >   State change
{            *   Illegal state
{            ()  Internal error condition
{}

?? EJECT ??

      TYPE
        incoming_commands = array [file_transfer_states] of nft$command_set,
        file_transfer_states = (start, xfer, enqf, errstp, wetp, wfini),

        parameter_09_message = record
          CASE boolean OF
          = FALSE =
            text: string (16),
          = TRUE =
            number_of_cards: string (8),
            bytes_transferred: string (8),
          CASEND,
        recend;

      VAR
        legal_receive_commands: [READ, STATIC] incoming_commands := [
              {  START: } [nfc$rft],
              {   XFER: } [nfc$go, nfc$stop],
              {   ENQF: } [nfc$stop],
              { ERRSTP: } [nfc$stop],
              {   WETP: } [nfc$rft, nfc$etp],
              {  WFINI: } [nfc$fini]];

      VAR
        required_params: [READ, STATIC] nft$required_param_on_command := [
              { Unknown: } [],
              { RFT:     } [nfc$protocol_id, nfc$facilities,
              nfc$minimum_timeout_interval, nfc$host_type, nfc$transfer_lid,
              nfc$system_routing_text, nfc$output_file_destination],
              { RPOS:    } [nfc$protocol_id, nfc$host_type],
              { RNEG:    } [nfc$protocol_id, nfc$state_of_transfer],
              { GO:      } [],
              { STOP:    } [nfc$state_of_transfer],
              { STOPR:   } [nfc$state_of_transfer],
              { ETP:     } [],
              { ETPR:    } [],
              { FINI:    } []];

      CONST
        max_data_area_size = 1000;

      VAR
        accounting_data: batch_input_accounting,
        account_message: parameter_09_message,
        elapsed_time: integer,
        end_time: ost$date_time,
        etpr_command: [READ, STATIC] nft$protocol_commands := nfc$etpr,
        etpr_params: [READ, STATIC] nft$parameter_set := [],
        file_size: amt$file_length,
        get_attributes: ^nat$get_attributes,
        get_accounting_data: ^nat$accounting_data_fields,
        ignored_params: nft$parameter_set,
        index: integer,
        modified_params: nft$parameter_set,
        msg_status: ost$status,
        ntf_p08_list: nft$directive_entry_list_head,
        ntf_queue_status: ost$status,
        number_of_cards: clt$integer,
        peer_accounting_information: ^string ( * ),
        peer_connect_data: ^string ( * ),
        protocol_consistent: boolean,
        rcv_status: ost$status,
        received_params: nft$parameter_set,
        rft_status: ost$status,
        rpos_command: [READ, STATIC] nft$protocol_commands := nfc$rpos,
        rpos_params: [READ, STATIC] nft$parameter_set :=
              [nfc$protocol_id, nfc$host_type],
        rneg_command: [READ, STATIC] nft$protocol_commands := nfc$rneg,
        rneg_params: [READ, STATIC] nft$parameter_set :=
              [nfc$protocol_id, nfc$state_of_transfer],
        set_status: ost$status,
        start_time: ost$date_time,
        state: file_transfer_states,
        status: ost$status,
        stopr_command: [READ, STATIC] nft$protocol_commands := nfc$stopr,
        stopr_params: nft$parameter_set,
        transfer_mode: nft$transfer_modes,
        transfer_status: ost$status;

?? EJECT ??

{}
{     BEGIN transfer_file
{}

      state := start;

{}
{     MAIN LOOP
{}

    /state_processor/
      WHILE TRUE DO

        control_block.local_status.normal := TRUE;
        control_block.state_of_transfer.normal := TRUE;

        { Get a protocol command from BTF/DI }
        nfp$receive_command (legal_receive_commands [state], required_params,
              control_block, received_params, ignored_params, modified_params,
              rcv_status);

        IF NOT control_block.path.path_connected THEN
          { Note that connection broken after sending a STOPR is legal }
          IF state <> wetp THEN
            osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error,
                  'BTFS transfer_file - connection broken -', msg_status);
            nfp$format_message_to_job_log (msg_status);
            nfp$format_message_to_job_log (rcv_status);
          IFEND;
          RETURN; {----->
        IFEND;

        IF NOT rcv_status.normal THEN
          nfp$format_message_to_job_log (rcv_status);
          IF rcv_status.condition = nfe$invalid_command_code THEN
            RETURN; {----->
          IFEND;
        IFEND;

        stopr_params := $nft$parameter_set [nfc$state_of_transfer];

        CASE state OF

        = start =
          { Note RFT is the only legal command for this state }
          pmp$get_compact_date_time (start_time, status);
          IF NOT status.normal THEN
            nfp$set_abnormal_if_normal (status, control_block.local_status);
            RETURN; {----->
          IFEND;
          process_rft (received_params, control_block, rft_status);
          IF (rcv_status.normal AND rft_status.normal) THEN
            { Send RPOS command to BTF/DI indicating we like RFT }
            nfp$send_command (rpos_command, rpos_params,
             $nft$parameter_set[ ], $nft$parameter_set[ ],
             control_block, status);
            state := xfer;
          ELSE
            { Send RNEG command to BTF/DI indicating we dislike RFT }
            nfp$send_command (rneg_command, rneg_params,
             $nft$parameter_set[ ], $nft$parameter_set[ ],
             control_block, status);
            state := errstp;
          IFEND;

        = xfer =
          { Note GO and STOP are the only legal commands for this state }
          IF (control_block.last_command_received = nfc$go) THEN

            { Perform data portion of file transfer }

            IF (p32.variant = nfc$p32_b101_ntf_id) THEN
              transfer_mode := nfc$transparent_data_mode;
            ELSE
              transfer_mode := nfc$coded_data_mode;
            IFEND;

            nfp$receive_file (control_block.path.network_file_id, control_block.
                  file_name, control_block.transfer_facilities,
                  transfer_mode, control_block.data_block_size,
                  control_block.time_out, nfc$p00_b101, nfc$network_nam,
                  osc$user_ring, control_block.protocol_trace,
                  file_size, protocol_consistent, transfer_status, status);

            IF NOT protocol_consistent THEN
              nfp$format_message_to_job_log (transfer_status);
              nfp$terminate_path (control_block.application, TRUE, control_block.
                    path, status);
              state := errstp;
            ELSEIF (NOT status.normal) OR (NOT transfer_status.normal) THEN
              state := errstp;
            ELSE
              state := enqf;
            IFEND;
          ELSE { control_block.last_command_received = nfc$stop }
            osp$set_status_abnormal (nfc$status_id,
                  nfe$transfer_rejected_message, '', set_status);
            nfp$set_abnormal_if_normal (set_status,
                  control_block.state_of_transfer);
            { Send STOPR command to BTF/DI indicating file transfer complete }
            nfp$send_command (stopr_command, stopr_params,
             $nft$parameter_set[ ], $nft$parameter_set[ ],
             control_block, status);
            state := wetp;
          IFEND;

        = enqf =
          { Note STOP is the only legal command for this state }
          IF rcv_status.normal THEN
            IF (p32.variant = nfc$p32_b101_ntf_id) THEN
              ntf_p08_list.head := NIL;
              ntf_p08_list.tail := NIL;
              nfp$ntf_receive_file (control_block, p17_param, p32_ntf_params,
                    p58_ntf_params, stopr_params, ntf_queue_status, status);
              IF status.normal AND (NOT ntf_queue_status.normal) THEN
                ntf_p08_list.head := NIL;
                ntf_p08_list.tail := NIL;
                nfp$enqueue_status_directive (ntf_queue_status, ntf_p08_list, status);
                IF NOT status.normal THEN
                  nfp$format_message_to_job_log (status);
                  RETURN; {----->
                IFEND;

                control_block.send_user_messages := ntf_p08_list.head;
              IFEND;
            ELSE

{ Collect communication accounting data

              pmp$get_compact_date_time (end_time, status);
              IF NOT status.normal THEN
                nfp$set_abnormal_if_normal (status, control_block.local_status);
                RETURN; {----->
              IFEND;
              pmp$compute_time_dif_in_seconds (start_time, end_time,
                    elapsed_time, status);
              IF NOT status.normal THEN
                nfp$set_abnormal_if_normal (status, control_block.local_status);
                RETURN; {----->
              IFEND;

{ Retrieve peer_accounting_information and peer_connect_data attributes.

              PUSH get_attributes: [1 .. 2];
              get_attributes^ [1].kind := nac$peer_accounting_information;
              PUSH get_attributes^ [1].peer_accounting_information: [[REP max_data_area_size OF cell]];
              get_attributes^ [2].kind := nac$peer_connect_data;
              PUSH get_attributes^ [2].peer_connect_data: [[REP max_data_area_size OF cell]];

              nap$get_attributes (control_block.path.network_file^, get_attributes^, status);
              IF NOT status.normal THEN
                nfp$set_abnormal_if_normal (status, control_block.local_status);
                RETURN; {----->
              IFEND;

              IF get_attributes^ [1].peer_accounting_info_length = 0 THEN
                peer_accounting_information := NIL;
              ELSE
                RESET get_attributes^ [1].peer_accounting_information;
                NEXT peer_accounting_information: [get_attributes^ [1].peer_accounting_info_length] IN
                      get_attributes^ [1].peer_accounting_information;
              IFEND;

              IF get_attributes^ [2].peer_connect_data_length = 0 THEN
                peer_connect_data := NIL;
              ELSE
                RESET get_attributes^ [2].peer_connect_data;
                NEXT peer_connect_data: [get_attributes^ [2].peer_connect_data_length] IN
                      get_attributes^ [2].peer_connect_data;
              IFEND;

              PUSH get_accounting_data: [1 .. 6];
              get_accounting_data^ [1].kind := nac$ca_di_system_name;
              get_accounting_data^ [2].kind := nac$ca_line_name;
              get_accounting_data^ [3].kind := nac$ca_line_subtype;
              get_accounting_data^ [4].kind := nac$ca_line_speed;
              get_accounting_data^ [5].kind := nac$ca_i_o_station_name;
              get_accounting_data^ [6].kind := nac$ca_device_name;
              nap$parse_accounting_data (peer_accounting_information, peer_connect_data,
                    get_accounting_data, status);
              IF NOT status.normal THEN
                nfp$set_abnormal_if_normal (status, control_block.local_status);
                RETURN; {----->
              IFEND;

              IF control_block.received_account_messages.head <> NIL THEN
                account_message.text := control_block.received_account_messages.
                      head^.line (1, #SIZE (parameter_09_message));
                clp$convert_string_to_integer (account_message.number_of_cards,
                      number_of_cards, status);
                IF NOT status.normal THEN
                  nfp$set_abnormal_if_normal (status, control_block.local_status);
                  RETURN; {----->
                IFEND;
              ELSE
                number_of_cards.value := 0;
              IFEND;

{ Set communication accounting data for submit_job

              accounting_data.size := #SIZE (nft$batch_input_accounting_data);
              accounting_data.data_block.connect_time := elapsed_time;
              accounting_data.data_block.number_of_cards :=
                    number_of_cards.value;
              accounting_data.data_block.di_system_name := osc$null_name;
              accounting_data.data_block.line_name := osc$null_name;
              accounting_data.data_block.line_subtype := osc$null_name;
              accounting_data.data_block.line_speed := 0;
              accounting_data.data_block.i_o_station_name := osc$null_name;
              accounting_data.data_block.device_name := osc$null_name;

              FOR index := 1 TO UPPERBOUND (get_accounting_data^) DO
                CASE get_accounting_data^ [index].kind OF
                = nac$ca_di_system_name =
                  accounting_data.data_block.di_system_name :=
                        get_accounting_data^ [index].di_system_name;
                = nac$ca_line_name =
                  accounting_data.data_block.line_name :=
                        get_accounting_data^ [index].line_name;
                = nac$ca_line_subtype =
                  accounting_data.data_block.line_subtype :=
                        get_accounting_data^ [index].line_subtype;
                = nac$ca_line_speed =
                  accounting_data.data_block.line_speed :=
                        get_accounting_data^ [index].line_speed;
                = nac$ca_i_o_station_name =
                  accounting_data.data_block.i_o_station_name :=
                        get_accounting_data^ [index].i_o_station_name;
                =nac$ca_device_name =
                  accounting_data.data_block.device_name :=
                        get_accounting_data^ [index].device_name;
                ELSE
                  ;
                CASEND;
              FOREND;

              submit_job (accounting_data, control_block, stopr_params, status);
            IFEND;
            IF NOT status.normal THEN
              RETURN; {----->
            IFEND;
          IFEND;
          { Send STOPR command to BTF/DI indicating file transfer complete }
          nfp$send_command (stopr_command, stopr_params,
             $nft$parameter_set[ ], $nft$parameter_set[ ],
             control_block, status);
          state := wetp;

        = errstp =
          { Note STOP is the only legal command for this state }
          osp$set_status_abnormal (nfc$status_id,
                nfe$transfer_rejected_message, '', set_status);
          nfp$set_abnormal_if_normal (set_status,
                control_block.state_of_transfer);
          { Send STOPR command to BTF/DI indicating file transfer complete }
          nfp$send_command (stopr_command, stopr_params,
             $nft$parameter_set[ ], $nft$parameter_set[ ],
             control_block, status);
          state := wetp;

        = wetp =
          { Note ETP and RFT are the only legal commands for this state }
          IF (control_block.last_command_received = nfc$etp) THEN
            { Send ETPR command to BTF/DI indicating protocol complete }
            nfp$send_command (etpr_command, etpr_params,
             $nft$parameter_set[ ], $nft$parameter_set[ ],
             control_block, status);
            state := wfini;
          ELSE { control_block.last_command_received = nfc$rft }
            pmp$get_compact_date_time (start_time, status);
            IF NOT status.normal THEN
              nfp$set_abnormal_if_normal (status, control_block.local_status);
              RETURN; {----->
            IFEND;
            process_rft (received_params, control_block, rft_status);
            IF (rcv_status.normal AND rft_status.normal) THEN
              { Send RPOS command to BTF/DI indicating we like RFT }
              nfp$send_command (rpos_command, rpos_params,
                    $nft$parameter_set[ ], $nft$parameter_set[ ],
                    control_block, status);
              state := xfer;
            ELSE
              { Send RNEG command to BTF/DI indicating we dislike RFT }
              nfp$send_command (rneg_command, rpos_params,
                    $nft$parameter_set[ ], $nft$parameter_set[ ],
                    control_block, status);
              state := errstp;
            IFEND;
          IFEND;

        = wfini =
          { Note FINI is the only legal command for this state }
          RETURN; {----->

        ELSE

          osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error,
                'BTFS transfer_file - CASE states -', status);
          nfp$format_message_to_job_log (status);
          RETURN; {----->

        CASEND;

{}
{     Check result of previous action
{}

        IF NOT status.normal THEN
          nfp$set_abnormal_if_normal (status, control_block.local_status);
        IFEND;

      WHILEND /state_processor/;

{}

    PROCEND transfer_file;

?? OLDTITLE, EJECT ??

{}
{   BEGIN nfp$btfs_service_task
{}

    status.normal := TRUE;

{}
{   Establish condition handler
{}

    conditions.selector := pmc$condition_combination;
    conditions.combination := $pmt$condition_combination
          [pmc$system_conditions, mmc$segment_access_condition,
          pmc$block_exit_processing, pmc$user_defined_condition,
          ifc$interactive_condition];

    pmp$establish_condition_handler (conditions, ^service_handler,
          ^establish_descriptor, status);
    IF NOT status.normal THEN
      nfp$format_message_to_job_log (status);
      RETURN; {----->
    IFEND;

{}
{   Initialize control block
{}

    nfp$initialize_control_block (

    { Application:      } nfc$application_btfs,
    { Data_Declaration: } nfc$p31_unspecified,
    { Requested Facs:   } $nft$parameter_03_value_set [nfc$ss_ack_required],
    { Required Facs:    } $nft$parameter_03_value_set [nfc$ss_ack_required],
    { Allowed Facs:     } $nft$parameter_03_value_set [nfc$ss_ack_required],
    { Protocol:         } nfc$p00_b101,
    { Mode of access:   } nfc$take,
    {                   } ^parameter_rules, control_block);

    pmp$get_unique_name (control_block.file_name, status);
    IF NOT status.normal THEN
      nfp$format_message_to_job_log (status);
      RETURN; {----->
    IFEND;

    control_block.remote_ring.value := osc$user_ring;

{}
{    Get the parameters passed to the BTFS service task by the BTFS boot
{    via the PMP$EXECUTE command
{}

    parameter_sequence := ^parameter_list;
    RESET parameter_sequence;
    NEXT parameter_value IN parameter_sequence;

    control_block.path := parameter_value^.path_info;
    PUSH control_block.path.network_file: [osc$max_name_size];
    control_block.path.network_file^ := parameter_value^.network_file;

    control_block.path.network_type := nfc$network_nam;

{}
{   Open network file
{}

    fsp$open_file (control_block.path.network_file^, amc$record, NIL, NIL, NIL,
          NIL, NIL, control_block.path.network_file_id, status);
    IF NOT status.normal THEN
      nfp$format_message_to_job_log (status);
      RETURN; {----->
    IFEND;

    control_block.path.path_connected := TRUE;

{}
{   Issue TASK STARTED message
{}

    IF nfc$trace_commands THEN
      log_message := '*BTFS TASK STARTED - CONNECTION # xxxxxxxx *';
      STRINGREP (log_message (35, * ), log_message_length,
            control_block.path.application_sequence_number: 8);
      pmp$log (log_message, log_status);
      IF NOT log_status.normal THEN
        nfp$format_message_to_job_log (log_status);
        RETURN; {----->
      IFEND;
    IFEND;

{}
{   Receive file(s)
{}

    transfer_file (control_block);

{}
{   Clean up
{}

    amp$return (control_block.file_name, ignore_status);

    pmp$disestablish_cond_handler (conditions, ignore_status);

{}

  PROCEND nfp$btfs_service_task;

{}

MODEND nfm$btf_server;
