?? RIGHT := 110 ??
?? NEWTITLE := 'NFM$BTF_CLIENT' ??
MODULE nfm$btf_client;

{
{  PURPOSE:
{     This module is used to service the Status and Control Facility (SCF)
{     and the Network Transfer Facility (NTF) requests to send data to a
{     specific destination.
{
{  DESCRIPTION:
{     The Batch Transfer Facility (BTF/VE) executes as an asynchronous task of
{     the calling task (SCF or NTF). Information is communicated between
{     BTF and the calling task in data packets using NFM$COMMON_TASK_COMMUNICATION. These
{     packets are the request to send data to a particular destination, and the
{     completion packet when the request has terminated (either normally or
{     abnormally).
{
{     The actual data transfer protocol is performed by NFM$RHF_PROTOCOL_ENGINE and
{     NFP$SEND_BATCH_FILE.
{

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc jmc$system_family
*copyc nat$network_address
*copyc nfc$command_definitions
*copyc nfc$parameter_00_definitions
*copyc nfc$parameter_03_definitions
*copyc nfc$parameter_04_definitions
*copyc nfc$parameter_06_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_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_51_definitions
*copyc nfc$parameter_52_definitions
*copyc nfc$parameter_53_definitions
*copyc nfc$parameter_54_definitions
*copyc nfc$parameter_55_definitions
*copyc nfc$parameter_59_definitions
*copyc nfc$parameter_60_definitions
*copyc nfc$parameter_definitions
*copyc nfe$batch_transfer_facility
*copyc nfe$batch_transfer_services
*copyc nft$application_file_descriptor
*copyc nft$batch_file_transport_info
*copyc nft$control_block
*copyc nft$command_set
*copyc nft$intertask_message
*copyc nft$last_command_received
*copyc nft$last_command_sent
*copyc nft$page_width
*copyc nft$parameter_set
*copyc nft$protocol_commands
*copyc nft$network_address
*copyc nft$network_type
*copyc nft$parameter_00_values
*copyc nft$parameter_25_definition
*copyc nft$parameter_31_type
*copyc nft$parameter_52_definition
*copyc nft$parameter_rules
*copyc nft$parameter_values
*copyc nft$protocol_parameters
*copyc nft$required_param_on_command
*copyc ost$name
*copyc sfe$counter_array_size_range
*copyc sfe$descriptive_data_size
*copyc sfe$invalid_statistic_name
*copyc sft$counter
*copyc sft$statistic_identifier
?? POP ??
*copyc amp$get_file_attributes
*copyc amp$get_next
*copyc amp$return
*copyc clp$convert_integer_to_rjstring
*copyc clp$convert_string_to_integer
*copyc clp$create_environment_variable
*copyc clp$delete_variable
*copyc clp$evaluate_token
*copyc clp$get_variable
*copyc clp$get_work_area
*copyc clp$include_line
*copyc clp$log_comment
*copyc clp$trimmed_string_size
*copyc fsp$open_file
*copyc jmp$emit_communication_stat
*copyc jmp$update_output_status
*copyc nap$display_message
*copyc nfp$begin_asynchronous_task
*copyc nfp$dispose_user_msg_to_log
*copyc nfp$end_async_communication
*copyc nfp$format_message_to_job_log
*copyc nfp$get_async_task_message
*copyc nfp$initialize_control_block
*copyc nfp$nam_request_connect
*copyc nfp$put_async_task_message
*copyc nfp$receive_command
*copyc nfp$send_batch_file
*copyc nfp$send_command
*copyc nfp$set_abnormal_if_normal
*copyc nfp$string_length
*copyc nfp$terminate_path
*copyc osp$append_status_parameter
*copyc osp$format_message
*copyc osp$set_status_abnormal
*copyc osp$set_status_from_condition
*copyc pmp$compute_time_dif_in_seconds
*copyc pmp$disestablish_cond_handler
*copyc pmp$establish_condition_handler
*copyc pmp$get_compact_date_time
*copyc pmp$get_unique_name
*copyc pmp$log
*copyc pmp$wait
*copyc sfp$convert_stat_name_to_code
*copyc sfp$emit_statistic
?? TITLE := 'Global Declarations Declared by This Module', EJECT ??

  CONST
    fa$comment_banner = 1,
    fa$data_mode = 2,
    fa$forms_code = 3,
    fa$page_length = 4,
    fa$page_width = 5,
    fa$routing_banner = 6,
    fa$vertical_print_density = 7,
    fa$vfu_load_procedure = 8,
    fa$max = 8;

  TYPE
    file_dispositions = (hold, print_and_hold, print_and_terminate, terminate);

  VAR
    btf_required_parameters: [READ, STATIC] nft$required_param_on_command := [
          { Null Command } [],
          { RFT } [nfc$protocol_id, nfc$facilities, nfc$file_length, nfc$file_name,
          nfc$minimum_timeout_interval, nfc$host_type, nfc$transfer_lid, nfc$system_routing_text],
          { 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 } []],

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

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

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

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

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

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

    parameter_06_rules: [READ, STATIC] nft$parameter_rules := [
          { A101 } [FALSE],
          { A102 } [FALSE],
          { B101 } [TRUE, nfc$p06_min_param_len, nfc$p06_max_param_len, [nfc$rft], [], [], [], FALSE]],

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

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

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

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

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

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

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

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

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

    parameter_18_rules: [READ, STATIC] nft$parameter_rules := [
          { A102 } [FALSE],
          { A101 } [FALSE],
          { B101 } [TRUE, nfc$min_param_size, nfc$min_param_size, [], [], [], [], FALSE]],

    parameter_19_rules: [READ, STATIC] nft$parameter_rules := [
          { A102 } [FALSE],
          { A101 } [FALSE],
          { B101 } [TRUE, nfc$min_param_size, nfc$min_param_size, [], [], [], [], FALSE]],

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

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

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

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

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

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

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

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

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

    parameter_29_rules: [READ, STATIC] nft$parameter_rules := [
          { A101 } [FALSE],
          { A102 } [FALSE],
          { B101 } [TRUE, nfc$p29_min_param_size_b101, nfc$p29_max_param_size_b101, [nfc$rft], [], [], [],
          FALSE ]],

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

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

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

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

    parameter_51_rules: [READ, STATIC] nft$parameter_rules := [
          { A101 } [FALSE],
          { A102 } [FALSE],
          { B101 } [TRUE, nfc$p51_min_param_length, nfc$p51_max_param_length, [], [], [], [], FALSE]],

    parameter_52_rules: [READ, STATIC] nft$parameter_rules := [
          { A101 } [FALSE],
          { A102 } [FALSE],
          { B101 } [TRUE, nfc$p52_min_param_length, nfc$p52_max_param_length, [], [], [], [], FALSE]],

    parameter_53_rules: [READ, STATIC] nft$parameter_rules := [
          { A101 } [FALSE],
          { A102 } [FALSE],
          { B101 } [TRUE, nfc$p53_min_param_length, nfc$p53_max_param_length, [], [], [], [], FALSE]],

    parameter_54_rules: [READ, STATIC] nft$parameter_rules := [
          { A101 } [FALSE],
          { A102 } [FALSE],
          { B101 } [TRUE, nfc$p54_min_param_length, nfc$p54_max_param_length, [], [], [], [], FALSE]],

    parameter_55_rules: [READ, STATIC] nft$parameter_rules := [
          { A101 } [FALSE],
          { A102 } [FALSE],
          { B101 } [TRUE, nfc$p55_min_param_length, nfc$p55_max_param_length, [], [], [], [], FALSE]],

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

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

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

    parameter_59_rules: [READ, STATIC] nft$parameter_rules := [
          { A101 } [FALSE],
          { A102 } [FALSE],
          { B101 } [TRUE, nfc$p59_min_param_length, nfc$p59_max_param_length, [], [], [], [], FALSE]],

    parameter_60_rules: [READ, STATIC] nft$parameter_rules := [
          { A101 } [FALSE],
          { A102 } [FALSE],
          { B101 } [TRUE, nfc$p60_min_param_len, nfc$p60_max_param_length, [], [], [], [], FALSE]],

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

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

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

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

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

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

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

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

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

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

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

?? TITLE := 'connection_initiation_phase', EJECT ??

{
{ PURPOSE:  Handle connection establishment phase.
{
{ DESCRIPTION:  This procedure initiates the creation of a connection to
{               the peer application.
{
{ INPUT PARAMETERS:
{            Network_address         : Address to establish a connection with
{            Station                 : Name of the station or remote system
{            Device                  : Name of the batch device or stream
{
{ INPUT/OUTPUT PARAMETERS:
{            Network_file_name       : name for network file
{            Control_block           : Record containing protocol, file and status information
{
{ OUTPUT PARAMETERS:
{            Status                  : Returned status
{
{ ALGORITHM:
{            Send connect request
{

  PROCEDURE connection_initiation_phase
    (    network_address: nat$network_address;
         station: ost$name;
         device: ost$name;
     VAR network_file_name: ost$name;
     VAR control_block: nft$control_block;
     VAR status: ost$status);

    CONST
      application_version = 1;

    VAR
      ignore_status: ost$status,
      trace_string: string (256),
      trace_string_length: integer;

    status.normal := TRUE;


    pmp$get_unique_name (network_file_name, status);
    IF status.normal THEN

{  Connect to the BTFS/DI address passed by calling task.

      control_block.path.network_file := ^network_file_name;
      IF control_block.protocol_trace THEN
        STRINGREP(trace_string, trace_string_length, 'BTF request connect STATION=',
              station(1, clp$trimmed_string_size(station)), ', DEVICE=', device(1,
              clp$trimmed_string_size(device)));
        pmp$log(trace_string(1, trace_string_length), ignore_status);
      IFEND;
      nfp$nam_request_connect (control_block.path.network_file^, control_block.application,
            control_block.application_server, network_address, application_version, station, device,
            control_block.path.network_file_id, status);

      IF status.normal THEN
        control_block.path.network_type := nfc$network_nam;
        control_block.path.path_connected := TRUE;
      ELSE
        nfp$set_abnormal_if_normal (status, control_block.local_status);
      IFEND;
    IFEND;

  PROCEND connection_initiation_phase;
?? OLDTITLE ??
?? NEWTITLE := 'convert_sequence_to_hex_string', EJECT ??

{ PURPOSE:
{   This procedure converts a sequence to a printable string.
{   The sequence is interpreted as hex digits.

    PROCEDURE convert_sequence_to_hex_string
      (    sequence: ^SEQ ( * );
           sequence_length: integer;
       VAR output_string: ^string ( * );
       VAR output_string_size: integer);

      TYPE
        mask_byte_to_integer = record
          case boolean of
          = FALSE =
            byte_value: string (1),
          = TRUE =
            integer_value: 0 .. 0ff(16),
          casend,
        recend;

      VAR
        conversion_mask: mask_byte_to_integer,
        i: integer,
        sequence_pointer: ^SEQ ( * ),
        single_value: string (4),
        local_status: ost$status,
        string_pointer: ^string ( * );

      sequence_pointer := sequence;
      RESET sequence_pointer;
      NEXT string_pointer: [sequence_length] IN sequence_pointer;

      output_string_size := 0;

      FOR i := 1 TO sequence_length DO
        conversion_mask.byte_value := string_pointer^ (i, 1);
        IF (output_string_size > 0) OR (conversion_mask.integer_value <> 0) THEN
          clp$convert_integer_to_rjstring (conversion_mask.integer_value + 100(16), 16, FALSE, '0',
                single_value, local_status);
          output_string^ (output_string_size + 1, 2) := single_value (3, 2);
          output_string_size := output_string_size + 2;
        IFEND;
      FOREND;

    PROCEND convert_sequence_to_hex_string;

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

{ PURPOSE:
{   This procedure executes the main batch output filter.

  PROCEDURE execute_batch_output_filter
    (    intertask_message: nft$intertask_message;
     VAR btf_completion_packet: nft$intertask_message;
     VAR control_block: nft$control_block;
     VAR file_attributes_var: ost$name;
     VAR file_disposition: file_dispositions;
     VAR file_disposition_var: ost$name;
     VAR output: amt$local_file_name;
     VAR output_file_contains_data: boolean;
     VAR output_file_var: ost$name;
     VAR statistics_file: amt$local_file_name;
     VAR statistics_file_contains_data: boolean;
     VAR status: ost$status);

{   TYPE
{    file_attributes: record
{        comment_banner: string 0..31 = $optional
{        data_mode: key
{          (coded, c)
{          (transparent, t)
{        keyend = $optional
{        forms_code : string 0..6 = $optional
{        page_length: integer 0..4398046511103 = $optional
{        page_width: integer 10..255 = $optional
{        routing_banner: string 0..31 = $optional
{        vertical_print_density: key
{          six, eight
{        keyend = $optional
{        vfu_load_procedure: any of
{          key
{            none
{          keyend
{          name
{        anyend = $optional
{      recend
{   TYPEND

?? PUSH (LISTEXT := ON) ??
?? FMT (FORMAT := OFF) ??

  VAR
   fa_type_specification : [STATIC, READ, cls$declaration_section] record
      header: clt$type_specification_header,
      name: string (15),
      qualifier: clt$record_type_qualifier,
      field_spec_1: clt$field_specification,
      element_type_spec_1: record
        header: clt$type_specification_header,
        qualifier: clt$string_type_qualifier,
      recend,
      field_spec_2: clt$field_specification,
      element_type_spec_2: record
        header: clt$type_specification_header,
        qualifier: clt$keyword_type_qualifier,
        keyword_specs: array [1 .. 4] of clt$keyword_specification,
      recend,
      field_spec_3: clt$field_specification,
      element_type_spec_3: record
        header: clt$type_specification_header,
        qualifier: clt$string_type_qualifier,
      recend,
      field_spec_4: clt$field_specification,
      element_type_spec_4: record
        header: clt$type_specification_header,
        qualifier: clt$integer_type_qualifier,
      recend,
      field_spec_5: clt$field_specification,
      element_type_spec_5: record
        header: clt$type_specification_header,
        qualifier: clt$integer_type_qualifier,
      recend,
      field_spec_6: clt$field_specification,
      element_type_spec_6: record
        header: clt$type_specification_header,
        qualifier: clt$string_type_qualifier,
      recend,
      field_spec_7: clt$field_specification,
      element_type_spec_7: record
        header: clt$type_specification_header,
        qualifier: clt$keyword_type_qualifier,
        keyword_specs: array [1 .. 2] of clt$keyword_specification,
      recend,
      field_spec_8: clt$field_specification,
      element_type_spec_8: record
        header: clt$type_specification_header,
        qualifier: clt$union_type_qualifier,
        type_size_1: clt$type_specification_size,
        element_type_spec_1: record
          header: clt$type_specification_header,
          qualifier: clt$keyword_type_qualifier,
          keyword_specs: array [1 .. 1] of clt$keyword_specification,
        recend,
        type_size_2: clt$type_specification_size,
        element_type_spec_2: record
          header: clt$type_specification_header,
          qualifier: clt$name_type_qualifier,
        recend,
      recend,
    recend := [
      [1, 15, clc$record_type], 'FILE_ATTRIBUTES', [8],
      ['COMMENT_BANNER                 ', clc$optional_field, 8], [[1, 0,
  clc$string_type], [0, 31, FALSE]],
      ['DATA_MODE                      ', clc$optional_field, 155], [[1, 0,
  clc$keyword_type], [4], [
        ['C                              ', clc$abbreviation_entry,
  clc$normal_usage_entry, 1],
        ['CODED                          ', clc$nominal_entry,
  clc$normal_usage_entry, 1],
        ['T                              ', clc$abbreviation_entry,
  clc$normal_usage_entry, 2],
        ['TRANSPARENT                    ', clc$nominal_entry,
  clc$normal_usage_entry, 2]]
        ],
      ['FORMS_CODE                     ', clc$optional_field, 8], [[1, 0,
  clc$string_type], [0, 6, FALSE]],
      ['PAGE_LENGTH                    ', clc$optional_field, 20], [[1, 0,
  clc$integer_type], [0, 4398046511103, 10]],
      ['PAGE_WIDTH                     ', clc$optional_field, 20], [[1, 0,
  clc$integer_type], [10, 255, 10]],
      ['ROUTING_BANNER                 ', clc$optional_field, 8], [[1, 0,
  clc$string_type], [0, 31, FALSE]],
      ['VERTICAL_PRINT_DENSITY         ', clc$optional_field, 81], [[1, 0,
  clc$keyword_type], [2], [
        ['EIGHT                          ', clc$nominal_entry,
  clc$normal_usage_entry, 2],
        ['SIX                            ', clc$nominal_entry,
  clc$normal_usage_entry, 1]]
        ],
      ['VFU_LOAD_PROCEDURE             ', clc$optional_field, 69], [[1, 0,
  clc$union_type], [[clc$keyword_type, clc$name_type],
        FALSE, 2],
        44, [[1, 0, clc$keyword_type], [1], [
          ['NONE                           ', clc$nominal_entry,
  clc$normal_usage_entry, 1]]
          ],
        5, [[1, 0, clc$name_type], [1, osc$max_name_size]]
        ]
      ];

?? FMT (FORMAT := ON) ??
?? POP ??



{ TYPE
{   file_disposition: key
{       (hold, h)
{       (print_and_hold, pah)
{       (print_and_terminate, pat)
{       (terminate, t)
{     keyend
{ TYPEND

?? PUSH (LISTEXT := ON) ??
?? FMT (FORMAT := OFF) ??

  VAR
    fd_type_specification : [STATIC, READ, cls$declaration_section] record
      header: clt$type_specification_header,
      name: string (16),
      qualifier: clt$keyword_type_qualifier,
      keyword_specs: array [1 .. 8] of clt$keyword_specification,
    recend := [
      [1, 16, clc$keyword_type], 'FILE_DISPOSITION', [8], [
      ['H                              ', clc$abbreviation_entry, clc$normal_usage_entry, 1],
      ['HOLD                           ', clc$nominal_entry, clc$normal_usage_entry, 1],
      ['PAH                            ', clc$abbreviation_entry, clc$normal_usage_entry, 2],
      ['PAT                            ', clc$abbreviation_entry, clc$normal_usage_entry, 3],
      ['PRINT_AND_HOLD                 ', clc$nominal_entry, clc$normal_usage_entry, 2],
      ['PRINT_AND_TERMINATE            ', clc$nominal_entry, clc$normal_usage_entry, 3],
      ['T                              ', clc$abbreviation_entry, clc$normal_usage_entry, 4],
      ['TERMINATE                      ', clc$nominal_entry, clc$normal_usage_entry, 4]]
      ];

?? FMT (FORMAT := ON) ??
?? POP ??

{ TYPE
{   output: file
{ TYPEND

?? PUSH (LISTEXT := ON) ??
?? FMT (FORMAT := OFF) ??

  VAR
    o_type_specification : [STATIC, READ, cls$declaration_section] record
      header: clt$type_specification_header,
      name: string (6),
    recend := [
      [1, 6, clc$file_type], 'OUTPUT'];

?? FMT (FORMAT := ON) ??

?? POP ??

    CONST
      filter_library = '$SYSTEM.BATCH_DEVICE_SUPPORT.STANDARD_FILTERS.COMMAND_LIBRARY';

    VAR
      file_name_size: integer,
      filter_command: string (512),
      filter_command_error: boolean,
      filter_status: ost$status,
      ignore_status: ost$status,
      last_size: integer,
      line_index: ost$status_message_line_count,
      local_status: ost$status,
      log_names: array [1..2] of ost$name,
      msg_line: string (80),
      page_width_string: string (3),
      preset: clt$data_value,
      size: integer,
      type_header: ^clt$type_specification_header,
      type_keyword_qualifier: ^clt$keyword_type_qualifier,
      type_mismatch: boolean,
      type_name: ^string ( * ),
      type_record_qualifier: ^clt$record_type_qualifier,
      var_access_mode: clt$data_access_mode,
      var_class: clt$variable_class,
      var_evaluation_method: clt$expression_eval_method,
      var_type_specification: ^clt$type_specification,
      var_value: ^clt$data_value,
      var_work_area_p: ^^clt$work_area;

?? NEWTITLE := 'check_if_file_contains_data', EJECT ??

{ PURPOSE:
{   This procedure checks is the specified file contains any data.

    PROCEDURE check_if_file_contains_data
      (    file: amt$local_file_name;
       VAR file_contains_data: boolean;
       VAR status: ost$status);

      VAR
        file_exists: boolean,
        file_previously_opened: boolean,
        get_attributes: ^amt$get_attributes;

      status.normal := TRUE;

      PUSH get_attributes: [1 .. 1];
      get_attributes^ [1].key := amc$null_attribute;
      amp$get_file_attributes (file, get_attributes^, file_exists, file_previously_opened,
            file_contains_data, status);

    PROCEND check_if_file_contains_data;
?? OLDTITLE ??

?? NEWTITLE := 'display_status_in_logs', EJECT ??

{ PURPOSE:
{   This displays a status message in the specified logs.
{
{ NOTE:
{   The lines to convert the status type into lines of text were copied
{   from the procedure NAP$DISPLAY_MESSAGE in order to use the
{   CLP$LOG_COMMENT interface instead of PMP$LOG.

    PROCEDURE display_status_in_logs
      (    status_message: ost$status;
           log_names: array [1..*] of ost$name);

      VAR
        ignore_status: ost$status,
        line_count: ^ost$status_message_line_count,
        line_index: ost$status_message_line_count,
        line_length: ^ost$status_message_line_size,
        message: ost$status_message,
        message_sequence: ^ost$status_message,
        text: ^ost$status_message_line;

      osp$format_message (status_message, osc$current_message_level, osc$max_status_message_line,
          message, ignore_status);
      message_sequence := ^message;
      RESET message_sequence;
      NEXT line_count IN message_sequence;

      FOR line_index := 1 TO line_count^ DO
        NEXT line_length IN message_sequence;
        NEXT text: [line_length^] IN message_sequence;
        clp$log_comment(text^, log_names, ignore_status);
      FOREND;

    PROCEND display_status_in_logs;
?? OLDTITLE ??
?? EJECT ??

    status.normal := TRUE;
    filter_status.normal := TRUE;

{ Create unique file name for STATISTICS_FILE parameter.

    pmp$get_unique_name (statistics_file, ignore_status);

{ Create SCL variables for VAR parameters.
{ Note that SCL variable names cannot start with a '$' so it is substituted
{ with a 'V'.

{ - Create OUTPUT variable.  Set it as unititialized.

    pmp$get_unique_name (output_file_var, ignore_status);
    output_file_var (1, 1) := 'V';

    preset.kind := clc$unspecified;

    clp$create_environment_variable (output_file_var, clc$job_scope, clc$read_write,
          clc$immediate_evaluation, #SEQ (o_type_specification), ^preset, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ - Create FILE_ATTRIBUTES variable.  Initialize it to values in the output file
{   descriptor.

    pmp$get_unique_name (file_attributes_var, ignore_status);
    file_attributes_var (1, 1) := 'V';

    preset.kind := clc$record;
    PUSH preset.field_values: [1 .. fa$max];

{ - Set COMMENT_BANNER.

    preset.field_values^ [fa$comment_banner].name := 'COMMENT_BANNER';
    PUSH preset.field_values^ [fa$comment_banner].value;
    preset.field_values^ [fa$comment_banner].value^.kind := clc$string;
    PUSH preset.field_values^ [fa$comment_banner].value^.string_value:
          [clp$trimmed_string_size (intertask_message.btf_file_descriptor.output_descriptor.comment_banner)];
    preset.field_values^ [fa$comment_banner].value^.string_value^ :=
          intertask_message.btf_file_descriptor.output_descriptor.comment_banner;

{ - Set DATA_MODE.

    preset.field_values^ [fa$data_mode].name := 'DATA_MODE';
    PUSH preset.field_values^ [fa$data_mode].value;
    preset.field_values^ [fa$data_mode].value^.kind := clc$keyword;
    IF intertask_message.btf_file_descriptor.output_descriptor.data_mode = jmc$coded_data THEN
      preset.field_values^ [fa$data_mode].value^.keyword_value := 'CODED';
    ELSE
      preset.field_values^ [fa$data_mode].value^.keyword_value := 'TRANSPARENT';
    IFEND;

{ - Set FORMS_CODE.

    preset.field_values^ [fa$forms_code].name := 'FORMS_CODE';
    PUSH preset.field_values^ [fa$forms_code].value;
    preset.field_values^ [fa$forms_code].value^.kind := clc$string;
    PUSH preset.field_values^ [fa$forms_code].value^.string_value:
          [clp$trimmed_string_size (intertask_message.btf_file_descriptor.output_descriptor.forms_code)];
    preset.field_values^ [fa$forms_code].value^.string_value^ :=
          intertask_message.btf_file_descriptor.output_descriptor.forms_code;

{ - Set PAGE_LENGTH.

    preset.field_values^ [fa$page_length].name := 'PAGE_LENGTH';
    PUSH preset.field_values^ [fa$page_length].value;
    preset.field_values^ [fa$page_length].value^.kind := clc$integer;
    preset.field_values^ [fa$page_length].value^.integer_value.value :=
          intertask_message.btf_file_descriptor.output_descriptor.page_length;
    preset.field_values^ [fa$page_length].value^.integer_value.radix := 10(10);
    preset.field_values^ [fa$page_length].value^.integer_value.radix_specified := FALSE;

{ - Set PAGE_WIDTH.

    preset.field_values^ [fa$page_width].name := 'PAGE_WIDTH';
    PUSH preset.field_values^ [fa$page_width].value;
    preset.field_values^ [fa$page_width].value^.kind := clc$integer;
    preset.field_values^ [fa$page_width].value^.integer_value.value :=
          intertask_message.btf_file_descriptor.output_descriptor.page_width;
    preset.field_values^ [fa$page_width].value^.integer_value.radix := 10(10);
    preset.field_values^ [fa$page_width].value^.integer_value.radix_specified := FALSE;

{ - Set ROUTING_BANNER.

    preset.field_values^ [fa$routing_banner].name := 'ROUTING_BANNER';
    PUSH preset.field_values^ [fa$routing_banner].value;
    preset.field_values^ [fa$routing_banner].value^.kind := clc$string;
    PUSH preset.field_values^ [fa$routing_banner].value^.string_value:
          [clp$trimmed_string_size (intertask_message.btf_file_descriptor.output_descriptor.routing_banner)];
    preset.field_values^ [fa$routing_banner].value^.string_value^ :=
          intertask_message.btf_file_descriptor.output_descriptor.routing_banner;

{ - Set VERTICAL_PRINT_DENSITY.

    preset.field_values^ [fa$vertical_print_density].name := 'VERTICAL_PRINT_DENSITY';
    PUSH preset.field_values^ [fa$vertical_print_density].value;
    preset.field_values^ [fa$vertical_print_density].value^.kind := clc$keyword;
    IF intertask_message.btf_file_descriptor.output_descriptor.vertical_print_density =
          jmc$vertical_print_density_6 THEN
      preset.field_values^ [fa$vertical_print_density].value^.keyword_value := 'SIX';
    ELSE
      preset.field_values^ [fa$vertical_print_density].value^.keyword_value := 'EIGHT';
    IFEND;

{ - Set VFU_LOAD_PROCEDURE.

    preset.field_values^ [fa$vfu_load_procedure].name := 'VFU_LOAD_PROCEDURE';
    PUSH preset.field_values^ [fa$vfu_load_procedure].value;
    IF intertask_message.btf_file_descriptor.output_descriptor.vfu_load_procedure = osc$null_name THEN
      preset.field_values^ [fa$vfu_load_procedure].value^.kind := clc$keyword;
      preset.field_values^ [fa$vfu_load_procedure].value^.keyword_value := 'NONE';
    ELSE
      preset.field_values^ [fa$vfu_load_procedure].value^.kind := clc$name;
      preset.field_values^ [fa$vfu_load_procedure].value^.name_value :=
            intertask_message.btf_file_descriptor.output_descriptor.vfu_load_procedure;
    IFEND;

    clp$create_environment_variable (file_attributes_var, clc$job_scope, clc$read_write,
          clc$immediate_evaluation, #SEQ (fa_type_specification), ^preset, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ - Create FILE_DISPOSITION variable.  Initialize it to PRINT_AND_TERMINATE.

    pmp$get_unique_name (file_disposition_var, ignore_status);
    file_disposition_var (1, 1) := 'V';

    preset.kind := clc$keyword;
    preset.keyword_value := 'PRINT_AND_TERMINATE';

    clp$create_environment_variable (file_disposition_var, clc$job_scope, clc$read_write,
          clc$immediate_evaluation, #SEQ (fd_type_specification), ^preset, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Build main filter command parameters.

    STRINGREP (filter_command, size, filter_library, '.MAIN_BATCH_OUTPUT_FILTER');
    last_size := size;

    STRINGREP (filter_command, size, filter_command (1, last_size), ' i=(',
          intertask_message.btf_file_descriptor.output_descriptor.system_file_name, ', ', '''',
          intertask_message.btf_file_descriptor.q_file_password, ''')');
    last_size := size;

    STRINGREP (filter_command, size, filter_command (1, last_size), ' o=', output_file_var);
    last_size := size;

    STRINGREP (filter_command, size, filter_command (1, last_size), ' sf=', statistics_file);
    last_size := size;

    STRINGREP (filter_command, size, filter_command (1, last_size), ' dev=',
          intertask_message.device_environment_variable);
    last_size := size;

    STRINGREP (filter_command, size, filter_command (1, last_size), ' fa=', file_attributes_var);
    last_size := size;

    STRINGREP (filter_command, size, filter_command (1, last_size), ' fd=', file_disposition_var);
    last_size := size;

{ Execute main batch output filter.

    clp$include_line (filter_command (1, last_size), FALSE, osc$null_name, filter_status);
    filter_command_error := NOT filter_status.normal;

    IF filter_status.normal THEN

    /filter_post_processing/
      BEGIN

        clp$get_work_area (#RING (^var_class), var_work_area_p, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

{ Find out if a value was returned for OUTPUT and if file contains data.

{ - Get the value of the OUTPUT variable.

        output_file_contains_data := FALSE;
        clp$get_variable (output_file_var, var_work_area_p^, var_class, var_access_mode,
              var_evaluation_method, var_type_specification, var_value, filter_status);
        IF NOT filter_status.normal THEN
          EXIT /filter_post_processing/;
        IFEND;

        IF (var_value <> NIL) THEN
          file_name_size := clp$trimmed_string_size (var_value^.file_value^);
          IF (file_name_size > 8) AND (var_value^.file_value^ (1, 8) = ':$LOCAL.') THEN
            output := var_value^.file_value^ (9, file_name_size - 8);
            check_if_file_contains_data (output, output_file_contains_data, status);
            IF NOT status.normal THEN
              RETURN;
            IFEND;
          ELSE
            osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                  filter_status);
            osp$append_status_parameter (osc$status_parameter_delimiter, 'OUTPUT not :$LOCAL file',
                  filter_status);
            EXIT /filter_post_processing/;
          IFEND;
        IFEND;

{ Find out if the STATISTICS_FILE contains data.

        check_if_file_contains_data (statistics_file, statistics_file_contains_data, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

{ Get the value of the FILE_DISPOSITION variable.

        clp$get_variable (file_disposition_var, var_work_area_p^, var_class, var_access_mode,
              var_evaluation_method, var_type_specification, var_value, filter_status);
        IF NOT filter_status.normal THEN
          EXIT /filter_post_processing/;
        IFEND;

{ - Verify that the type of variable read is same as the one that was created.

        type_mismatch := TRUE;
        RESET var_type_specification;
        NEXT type_header IN var_type_specification;
        IF (type_header^.version = fd_type_specification.header.version) AND
              (type_header^.name_size = fd_type_specification.header.name_size) AND
              (type_header^.kind = fd_type_specification.header.kind) THEN
          NEXT type_name: [type_header^.name_size] IN var_type_specification;
          IF type_name <> NIL THEN
            IF type_name^ = fd_type_specification.name THEN
              NEXT type_keyword_qualifier IN var_type_specification;
              IF type_keyword_qualifier <> NIL THEN
                IF type_keyword_qualifier^ = fd_type_specification.qualifier THEN
                  type_mismatch := FALSE;
                IFEND;
              IFEND;
            IFEND;
          IFEND;
        IFEND;
        IF (type_mismatch OR (var_value = NIL)) THEN
          osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                filter_status);
          osp$append_status_parameter (osc$status_parameter_delimiter, 'FILE_DISPOSITION var type mismatch',
                filter_status);
          EXIT /filter_post_processing/;
        IFEND;

        IF var_value^.keyword_value = 'HOLD' THEN
          file_disposition := hold;
        ELSEIF var_value^.keyword_value = 'PRINT_AND_HOLD' THEN
          file_disposition := print_and_hold;
        ELSEIF var_value^.keyword_value = 'PRINT_AND_TERMINATE' THEN
          file_disposition := print_and_terminate;
        ELSEIF var_value^.keyword_value = 'TERMINATE' THEN
          file_disposition := terminate;
        ELSE
          osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                filter_status);
          osp$append_status_parameter (osc$status_parameter_delimiter, 'FILE_DISPOSITION keyword error',
                filter_status);
          EXIT /filter_post_processing/;
        IFEND;
        IF ((file_disposition = hold) OR (file_disposition = print_and_hold)) AND
              (NOT intertask_message.scfs_can_handle_filter_hold) THEN
          osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                filter_status);
          osp$append_status_parameter (osc$status_parameter_delimiter,
                'Version of SCFS cannot handle FILE_DISPOSITION of HOLD.', filter_status);
          EXIT /filter_post_processing/;
        IFEND;

        IF (file_disposition = print_and_hold) OR (file_disposition = print_and_terminate) THEN

{ If file is to print then update RFT parameter values with FILE_ATTRIBUTES
{ returned by filter.
{ NOTE:  PAGE_LENGTH is ignored since this value is not transmitted to BTFS/DI.

          clp$get_variable (file_attributes_var, var_work_area_p^, var_class, var_access_mode,
                var_evaluation_method, var_type_specification, var_value, filter_status);
          IF NOT filter_status.normal THEN
            EXIT /filter_post_processing/;
          IFEND;

{ - Verify that the type of variable read is same as the one that was created.

          type_mismatch := TRUE;
          RESET var_type_specification;
          NEXT type_header IN var_type_specification;
          IF (type_header^.version = fa_type_specification.header.version) AND
                (type_header^.name_size = fa_type_specification.header.name_size) AND
                (type_header^.kind = fa_type_specification.header.kind) THEN
            NEXT type_name: [type_header^.name_size] IN var_type_specification;
            IF type_name <> NIL THEN
              IF type_name^ = fa_type_specification.name THEN
                NEXT type_record_qualifier IN var_type_specification;
                IF type_record_qualifier <> NIL THEN
                  IF type_record_qualifier^ = fa_type_specification.qualifier THEN
                    type_mismatch := FALSE;
                  IFEND;
                IFEND;
              IFEND;
            IFEND;
          IFEND;
          IF (type_mismatch OR (var_value = NIL) OR (var_value^.field_values = NIL)) THEN
            osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                  filter_status);
            osp$append_status_parameter (osc$status_parameter_delimiter, 'FILE_ATTRIBUTES var type mismatch',
                  filter_status);
            EXIT /filter_post_processing/;
          IFEND;

{ - Update USER_BANNER_MESSAGE (from COMMENT_BANNER).

          IF var_value^.field_values^ [fa$comment_banner].name = 'COMMENT_BANNER' THEN
            control_block.user_banner_message.size := clp$trimmed_string_size
                  (var_value^.field_values^ [fa$comment_banner].value^.string_value^);
            IF control_block.user_banner_message.size > jmc$output_comment_banner_size THEN
              control_block.user_banner_message.size := jmc$output_comment_banner_size;
            IFEND;
            control_block.user_banner_message.value := var_value^.field_values^ [fa$comment_banner].value^.
                  string_value^ (1, control_block.user_banner_message.size);
          ELSE
            osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                  filter_status);
            osp$append_status_parameter (osc$status_parameter_delimiter, 'FILE_ATTRIBUTES type error (CB)',
                  filter_status);
            EXIT /filter_post_processing/;
          IFEND;

{ - Update BANNER_ROUTING_TEXT (from ROUTING_BANNER).

          IF var_value^.field_values^ [fa$routing_banner].name = 'ROUTING_BANNER' THEN
            control_block.banner_routing_text.size := clp$trimmed_string_size
                  (var_value^.field_values^ [fa$routing_banner].value^.string_value^);
            IF control_block.banner_routing_text.size > jmc$output_routing_banner_size THEN
              control_block.banner_routing_text.size := jmc$output_routing_banner_size;
            IFEND;
            control_block.banner_routing_text.value := var_value^.field_values^ [fa$routing_banner].value^.
                  string_value^ (1, control_block.banner_routing_text.size);
          ELSE
            osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                  filter_status);
            osp$append_status_parameter (osc$status_parameter_delimiter, 'FILE_ATTRIBUTES type error (RB)',
                  filter_status);
            EXIT /filter_post_processing/;
          IFEND;

{ - Update VFU_LOAD_PROCEDURE.

          IF var_value^.field_values^ [fa$vfu_load_procedure].name = 'VFU_LOAD_PROCEDURE' THEN
            IF var_value^.field_values^ [fa$vfu_load_procedure].value^.kind = clc$name THEN
              control_block.vfu_load_procedure.value := var_value^.field_values^ [fa$vfu_load_procedure].
                    value^.name_value;
            ELSEIF var_value^.field_values^ [fa$vfu_load_procedure].value^.kind = clc$keyword THEN
              control_block.vfu_load_procedure.value := '';
            ELSE
              osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                    filter_status);
              osp$append_status_parameter (osc$status_parameter_delimiter,
                    'FILE_ATTRIBUTES.VFU_LOAD_PROCEDURE kind error', filter_status);
              EXIT /filter_post_processing/;
            IFEND;
            control_block.vfu_load_procedure.size := clp$trimmed_string_size
                  (control_block.vfu_load_procedure.value);
          ELSE
            osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                  filter_status);
            osp$append_status_parameter (osc$status_parameter_delimiter, 'FILE_ATTRIBUTES type error (VLP)',
                  filter_status);
            EXIT /filter_post_processing/;
          IFEND;

{ The following RFT parameters are updated only when the filter has created
{ an output file.

          IF output_file_contains_data THEN

{ - Update DATA_DECLARATION (from DATA_MODE).

            IF var_value^.field_values^ [fa$data_mode].name = 'DATA_MODE' THEN
              IF var_value^.field_values^ [fa$data_mode].value^.keyword_value = 'CODED' THEN
                control_block.data_declaration := nfc$p31_ascii_c8;
              ELSEIF var_value^.field_values^ [fa$data_mode].value^.keyword_value = 'TRANSPARENT' THEN
                control_block.data_declaration := nfc$p31_undef_unstructured_uu;
              ELSE
                osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                      filter_status);
                osp$append_status_parameter (osc$status_parameter_delimiter,
                      'FILE_ATTRIBUTES.DATA_MODE keyword error', filter_status);
                EXIT /filter_post_processing/;
              IFEND;
            ELSE
              osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                    filter_status);
              osp$append_status_parameter (osc$status_parameter_delimiter, 'FILE_ATTRIBUTES type error (DM)',
                    filter_status);
              EXIT /filter_post_processing/;
            IFEND;

{ - Update ECHO_TEXT (from PAGE_WIDTH).

            IF var_value^.field_values^ [fa$page_width].name = 'PAGE_WIDTH' THEN
              IF var_value^.field_values^ [fa$page_width].value^.integer_value.value <
                    nfc$minimum_page_width THEN
                var_value^.field_values^ [fa$page_width].value^.integer_value.value := nfc$minimum_page_width;
              ELSEIF var_value^.field_values^ [fa$page_width].value^.integer_value.value >
                    nfc$maximum_page_width THEN
                var_value^.field_values^ [fa$page_width].value^.integer_value.value := nfc$maximum_page_width;
              IFEND;
              clp$convert_integer_to_rjstring (var_value^.field_values^ [fa$page_width].value^.integer_value.
                    value, {radix} 10, {include_radix} FALSE, {filler} '0', page_width_string, status);
              IF NOT status.normal THEN
                RETURN;
              IFEND;
              IF control_block.send_echo_text.first_text <> NIL THEN
                control_block.send_echo_text.first_text^.value := page_width_string;
              ELSE
                osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                      filter_status);
                osp$append_status_parameter (osc$status_parameter_delimiter, 'ECHO_TEXT not initialized',
                      filter_status);
                EXIT /filter_post_processing/;
              IFEND;
            ELSE
              osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                    filter_status);
              osp$append_status_parameter (osc$status_parameter_delimiter, 'FILE_ATTRIBUTES type error (PW)',
                    filter_status);
              EXIT /filter_post_processing/;
            IFEND;

{ - Update VERTICAL_PRINT_DENSITY.

            IF var_value^.field_values^ [fa$vertical_print_density].name = 'VERTICAL_PRINT_DENSITY' THEN
              IF var_value^.field_values^ [fa$vertical_print_density].value^.keyword_value = 'SIX' THEN
                control_block.vertical_print_density := jmc$vertical_print_density_6;
              ELSEIF var_value^.field_values^ [fa$vertical_print_density].value^.keyword_value = 'EIGHT' THEN
                control_block.vertical_print_density := jmc$vertical_print_density_8;
              ELSE
                osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                      filter_status);
                osp$append_status_parameter (osc$status_parameter_delimiter,
                      'FILE_ATTRIBUTES.VPD keyword error', filter_status);
                EXIT /filter_post_processing/;
              IFEND;
            ELSE
              osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'EXECUTE_BATCH_OUTPUT_FILTER',
                    filter_status);
              osp$append_status_parameter (osc$status_parameter_delimiter, 'FILE_ATTRIBUTES type error (VPD)',
                    filter_status);
              EXIT /filter_post_processing/;
            IFEND;

          IFEND;
        IFEND;

      END /filter_post_processing/;
    IFEND;

    IF NOT filter_status.normal THEN

      log_names [1] := 'JOB';
      log_names [2] := 'SYSTEM';

{ Determine if the error was because the MAIN_BATCH_OUTPUT_FILTER is not
{ available.  If this is the case, issue a warning and print the queue file.

      IF filter_command_error THEN
        STRINGREP (filter_command, size, '$system.display_command_information c=', filter_library,
              '.MAIN_BATCH_OUTPUT_FILTER', ' o=$null');

        clp$include_line (filter_command (1, last_size), FALSE, osc$null_name, local_status);

        IF NOT local_status.normal THEN
          btf_completion_packet.filter_aborted := FALSE;
          file_disposition := print_and_terminate;
          clp$log_comment ('*** BATCH OUTPUT FILTER ERROR - Cannot execute MAIN_BATCH_OUTPUT_FILTER:',
              log_names, ignore_status);
          display_status_in_logs (filter_status, log_names);
          RETURN;
        IFEND;
      IFEND;

{ There are problems with the batch output filter.  Hold the file and log
{ significant info - SCF will notify operator of filter error.

      btf_completion_packet.filter_aborted := TRUE;
      file_disposition := hold;
      clp$log_comment ('*** BATCH OUTPUT FILTER ERROR ***', log_names, ignore_status);
      clp$log_comment ('***   STATUS:', log_names, ignore_status);
      display_status_in_logs (filter_status, log_names);
      STRINGREP (msg_line, size, '***   SYSTEM_FILE_NAME:  ',
            intertask_message.btf_file_descriptor.output_descriptor.system_file_name);
      clp$log_comment (msg_line (1, size), log_names, ignore_status);
      STRINGREP (msg_line, size, '***   STATION:  ', intertask_message.btf_file_descriptor.output_descriptor.
            station);
      clp$log_comment (msg_line (1, size), log_names, ignore_status);
      STRINGREP (msg_line, size, '***   DEVICE:  ', intertask_message.btf_file_descriptor.output_descriptor.
            device);
      clp$log_comment (msg_line (1, size), log_names, ignore_status);
    IFEND

  PROCEND execute_batch_output_filter;
?? OLDTITLE ??
?? NEWTITLE := 'init_and_data_transfer_phase', EJECT ??

{
{ PURPOSE:   This routine performs the initiation and data transfer phases
{            of the A-A protocol for a file transfer.
{
{ DESCRIPTION:
{            This routine is state table driven.  The state table takes into
{            account two things: last command sent and last command received.
{            The actions possible are send command, receive command and
{            transfer file.
{
{ INPUT PARAMETERS:
{            File Descriptor      : Input or Output Descriptor
{
{ INPUT/OUTPUT PARAMETERS:
{            Control_block        : Record containing protocol, file and status information
{
{ OUTPUT PARAMETERS:
{            Status               : Return status
{
{ ALGORITHM:
{            WHILE not done DO
{              Get state (last_sent, last_received)
{              Case state Of
{              = send_command     =>  nfp$send_command
{              = receive_command  =>  nfp$receive_command
{              = transfer_file    =>  nfp$send_batch_file
{              = terminate        =>  exit procedure
{              Casend
{              If rneg situation, set next state
{            WHILEND
{

  PROCEDURE init_and_data_transfer_phase
    (    file_descriptor: nft$application_file_descriptor;
         local_file_name: amt$local_file_name;
         ntf_local_file: boolean;
     VAR control_block: nft$control_block;
     VAR status: ost$status);

    CONST
      btf_number_of_protocol_states = 8;

    TYPE
      btf_protocol_actions = (nfc$btf_send_command, nfc$btf_receive_command, nfc$btf_start_transfer,
            nfc$btf_terminate),

      btf_protocol_states = array [1 .. btf_number_of_protocol_states] of nft$btf_state_table,

      nft$btf_state_table = record
        last_command_sent: nft$last_command_sent,
        last_command_received: nft$last_command_received,
        case action: btf_protocol_actions of
        = nfc$btf_send_command =
          send_command: nft$protocol_commands,
          send_parameters: nft$parameter_set,
        = nfc$btf_receive_command =
          legal_receive_commands: nft$command_set,
        = nfc$btf_start_transfer =
          transfer_send_command: nft$protocol_commands,
          transfer_send_parameters: nft$parameter_set,
        = nfc$btf_terminate =
        casend,
      recend,

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

    VAR
      btf_protocol: [READ, STATIC] btf_protocol_states := [

      [nfc$unknown_command,         { Last Command Sent }
            nfc$unknown_command,         { Last Command Received }
            nfc$btf_send_command,        { Send Command To Remote }
            nfc$rft,                     { Command to Send }
            [nfc$protocol_id, nfc$facilities, nfc$file_length, nfc$max_block_size, nfc$file_name,
            nfc$accounting_limit, nfc$minimum_timeout_interval, nfc$host_type, nfc$transfer_lid,
            nfc$data_declaration, nfc$system_routing_text]],

      [nfc$rft,                     { Last Command Sent }
            nfc$unknown_command,         { Last Command Received }
            nfc$btf_receive_command,     { Receive Command From Remote }
            [nfc$rpos, nfc$rneg]],       { Command to Receive }

      [nfc$rft,                     { Last Command Sent }
            nfc$rpos,                    { Last Command Received }
            nfc$btf_start_transfer,      { Send Command To Remote }
            nfc$go,                      { Command to Send }
            []],

      [nfc$rft,                     { Last Command Sent }
            nfc$rneg,                    { Last Command Received }
            nfc$btf_send_command,        { Send Command To Remote }
            nfc$stop,                    { Command to Send }
            [nfc$state_of_transfer]],

      [nfc$go,                      { Last Command Sent }
            nfc$rpos,                    { Last Command Received }
            nfc$btf_send_command,        { Send Command To Remote }
            nfc$stop,                    { Command to Send }
            [nfc$state_of_transfer]],

      [nfc$stop,                    { Last Command Sent }
            nfc$rneg,                    { Last Command Received }
            nfc$btf_receive_command,     { Receive Command From Remote }
            [nfc$stopr]],                { Command to Receive }

      [nfc$stop,                    { Last Command Sent }
            nfc$rpos,                    { Last Command Received }
            nfc$btf_receive_command,     { Receive Command From Remote }
            [nfc$stopr]],                { Command to Receive }

      [nfc$stop,                    { Last Command Sent }
            nfc$stopr,                   { Last Command Received }
            nfc$btf_terminate]],         { Terminate Transfer }

      account_message: parameter_09_message,
      destination_usage: jmt$destination_usage,
      device_type: jmt$output_device_type,
      elapsed_time: integer,
      end_time: ost$date_time,
      ignored_params: nft$parameter_set,
      ignore_status: ost$status,
      index: 1 .. btf_number_of_protocol_states,
      local_status: ost$status,
      modified_params: nft$parameter_set,
      new_state: btf_protocol_actions,
      number_of_lines: clt$integer,
      output_statistics: ^jmt$output_file_statistic_data,
      protocol_consistent: boolean,
      received_params: nft$parameter_set,
      send_parameters: nft$parameter_set,
      start_time: ost$date_time,
      state_known: boolean,
      statistic_data: jmt$comm_acct_statistic_data,
      system_file_name: jmt$system_supplied_name,
      transfer_mode: nft$transfer_modes,
      transfer_status: ost$status;


    status.normal := TRUE;
    control_block.negotiate_protocol := FALSE;
    control_block.last_command_sent := nfc$unknown_command;
    control_block.last_command_received := nfc$unknown_command;
    control_block.state_of_transfer.normal := TRUE;
    control_block.local_status.normal := TRUE;
    control_block.remote_status.normal := TRUE;
    control_block.send_operator_messages := NIL;
    control_block.send_user_messages := NIL;
    control_block.send_account_messages := NIL;
    control_block.send_errorlog_messages := NIL;
    transfer_status.normal := TRUE;
    protocol_consistent := TRUE;

    CASE control_block.data_declaration OF
    = nfc$p31_host_dependent_uh =
      transfer_mode := nfc$ve_to_ve_mode;
    = nfc$p31_unspecified, nfc$p31_ascii_c6, nfc$p31_ascii_c8 =
      transfer_mode := nfc$coded_data_mode;
    = nfc$p31_undef_unstructured_uu =
      transfer_mode := nfc$transparent_data_mode;
    ELSE
    CASEND;

    IF file_descriptor.file_kind = nfc$output_file THEN
      destination_usage := file_descriptor.output_descriptor.output_destination_usage;
      device_type := file_descriptor.output_descriptor.device_type;
    ELSE {file_descriptor.file_kind = nfc$input_file}
      destination_usage := file_descriptor.input_descriptor.job_destination_usage;
{  Set device_type to a value that will ensure that VPD and VLP are not sent on RFT.
{  Don't rely on destination_usage to be set correctly.
      device_type := jmc$output_device_punch;
    IFEND;

{  Continue with protocol until a STOPR is received or connection is terminated

  /advance_state_table_loop/
    WHILE control_block.path.path_connected DO
      state_known := FALSE;

    /state_loop/
      FOR index := LOWERVALUE (index) TO UPPERVALUE (index) DO
        IF ((btf_protocol [index].last_command_sent = control_block.last_command_sent) AND
              (btf_protocol [index].last_command_received = control_block.last_command_received)) THEN
          state_known := TRUE;
          EXIT /state_loop/ {----->
        IFEND;
      FOREND /state_loop/;

      IF NOT state_known THEN
        osp$set_status_abnormal (nfc$status_id, nfe$invalid_command_code, ' ', status);
        EXIT /advance_state_table_loop/ {----->
      IFEND;

      new_state := btf_protocol [index].action;

      CASE new_state OF

      = nfc$btf_send_command =

        send_parameters := btf_protocol [index].send_parameters;

        IF btf_protocol [index].send_command = nfc$rft THEN
          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;
          IF control_block.send_job_name.size <> 0 THEN
            send_parameters := send_parameters + $nft$parameter_set [nfc$job_name];
          IFEND;
          IF control_block.user_file_name.size <> 0 THEN
            send_parameters := send_parameters + $nft$parameter_set [nfc$user_file_name];
          IFEND;
          IF destination_usage <> jmc$ntf_usage THEN
            IF control_block.banner_date_and_time.size <> 0 THEN
              send_parameters := send_parameters + $nft$parameter_set [nfc$banner_date_and_time];
            IFEND;
            IF control_block.banner_routing_text.size <> 0 THEN
              send_parameters := send_parameters + $nft$parameter_set [nfc$banner_routing_text];
            IFEND;
            IF control_block.user_banner_message.size <> 0 THEN
              send_parameters := send_parameters + $nft$parameter_set [nfc$user_banner_text];
            IFEND;
            IF control_block.installation_banner_message.size <> 0 THEN
              send_parameters := send_parameters + $nft$parameter_set [nfc$installation_banner_text];
            IFEND;
            send_parameters := send_parameters + $nft$parameter_set [nfc$echo];
          IFEND;
          IF ((destination_usage = jmc$public_usage ) OR (destination_usage = jmc$private_usage))
                AND (device_type = jmc$output_device_printer) THEN
            IF control_block.vertical_print_density >= jmc$vertical_print_density_6 THEN
              send_parameters := send_parameters + $nft$parameter_set [nfc$vertical_print_density];
            IFEND;
            IF control_block.vfu_load_procedure.size <> 0 THEN
              send_parameters := send_parameters + $nft$parameter_set [nfc$vfu_load_procedure];
            IFEND;
          IFEND;
        IFEND;

        nfp$send_command (btf_protocol [index].send_command, send_parameters,
             $nft$parameter_set[ ], $nft$parameter_set[ ],
             control_block, status);

      = nfc$btf_receive_command =

        nfp$receive_command (btf_protocol [index].legal_receive_commands, btf_required_parameters,
              control_block, received_params, ignored_params, modified_params, status);

        IF (status.normal) AND (control_block.received_user_messages.head <> NIL) THEN
          nfp$dispose_user_msg_to_log (control_block.received_user_messages);
        IFEND;

{  NOTE:  Here is a trick to make the state table work for two odd conditions.
{         If RPOS was received, but an error occured, the application should treat the error as
{         if an RNEG was received.  If RPOS was received, but protocol negotiation was requested
{         by the server, the initiator should treat the condition as an RNEG

        IF (control_block.last_command_received = nfc$rpos) THEN
          IF (NOT status.normal) THEN
            control_block.last_command_received := nfc$rneg;
            osp$set_status_abnormal (nfc$status_id, nfe$protocol_anomaly, ' ',
                  control_block.state_of_transfer);
          ELSE
            IF control_block.negotiate_protocol THEN
              control_block.last_command_received := nfc$rneg;
            IFEND;
          IFEND;
        IFEND;

      = nfc$btf_start_transfer =

{  Send the file transfer protocol command to BTFS/DI.

        nfp$send_command (btf_protocol [index].transfer_send_command,
              btf_protocol [index].transfer_send_parameters,
              $nft$parameter_set[ ], $nft$parameter_set[ ],
              control_block, status);
        IF status.normal THEN

{  Transfer the file to the destination.

          system_file_name := control_block.send_file_name.value (1, jmc$system_supplied_name_size);
          IF ntf_local_file THEN
            transfer_mode := nfc$transparent_data_mode;
          IFEND;

          nfp$send_batch_file (control_block.path.network_file_id, control_block.path.network_file^,
                system_file_name, local_file_name, control_block.transfer_facilities, transfer_mode,
                control_block.data_block_size, control_block.time_out, control_block.protocol_in_use,
                control_block.destination_usage, control_block.queue_file_password,
                control_block.disposition_code, control_block.protocol_trace, control_block.file_position,
                protocol_consistent, transfer_status, status);

          IF NOT protocol_consistent THEN
            nfp$terminate_path (control_block.application, TRUE, control_block.path, ignore_status);
          IFEND;

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

          IF (control_block.state_of_transfer.normal) AND protocol_consistent THEN
            control_block.state_of_transfer := transfer_status;
          IFEND;
        IFEND;

      = nfc$btf_terminate =

{ Transfer of file complete, emit communication statistic and exit procedure

        IF destination_usage <> jmc$ntf_usage THEN
          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;

          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_lines,
                  number_of_lines, status);
            IF NOT status.normal THEN
              nfp$set_abnormal_if_normal (status, control_block.local_status);
              RETURN; {----->
            IFEND;
          ELSE
            number_of_lines.value := 0;
          IFEND;

          PUSH output_statistics;

          statistic_data.statistic_id := jmc$ca_output_file;
          statistic_data.output_file := output_statistics;
          output_statistics^.connect_time := elapsed_time;
          output_statistics^.number_of_lines := number_of_lines.value;
          output_statistics^.output_descriptor := file_descriptor.output_descriptor;
          output_statistics^.network_file_name := control_block.path.network_file^;

          jmp$emit_communication_stat (statistic_data);
        IFEND;

        EXIT /advance_state_table_loop/; {----->

      ELSE
        osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'invalid btf state table action',
              status);
        RETURN;
      CASEND;

{  Save first abnormal status.

      IF NOT status.normal THEN
        nfp$set_abnormal_if_normal (status, control_block.local_status);
        IF (status.condition = nfe$invalid_protocol_command) OR
              (status.condition = nfe$invalid_param_count) OR
              (status.condition = nfe$invalid_command_code) THEN
          RETURN;
        IFEND;
      IFEND;

    WHILEND /advance_state_table_loop/;

  PROCEND init_and_data_transfer_phase;
?? TITLE := 'nfp$btf_client', EJECT ??

  PROCEDURE [XDCL] nfp$btf_client
    (    program_parameters: pmt$program_parameters;
     VAR status: ost$status);

    VAR
      abort_message: nft$intertask_message,
      async_status: ost$status,
      block_exit_condition: [READ, STATIC] pmt$condition :=
            [pmc$block_exit_processing, [pmc$block_exit, pmc$program_termination, pmc$program_abort]],
      btf_completion_packet: nft$intertask_message,
      connected_task: pmt$task_id,
      control_block: nft$control_block,
      copies: jmt$output_copy_count,
      descriptor_packet: nft$intertask_message,
      device: ost$name,
      error_descriptor: ^pmt$established_handler,
      file_attributes_var: ost$name,
      file_disposition: file_dispositions,
      file_disposition_var: ost$name,
      file_position: jmt$output_file_position,
      ignore_queue_id: pmt$queue_connection,
      ignore_status: ost$status,
      local_file_name: amt$local_file_name,
      local_status: ost$status,
      network_file_name: ost$name,
      ntf_local_file: boolean,
      output: amt$local_file_name,
      output_file_contains_data: boolean,
      output_file_var: ost$name,
      output_status_updates: ^jmt$output_status_updates,
      retry_count: integer,
      selected_device: ost$name,
      selected_station: ost$name,
      station: ost$name,
      statistics_file: amt$local_file_name,
      statistics_file_contains_data: boolean,
      terminated_message: [STATIC] string (46) := '**** $0000_0000_AAA_0000 Terminated by filter.',
      transfer_count: 0 .. nfc$max_transfer_size,
      transfer_file: boolean;

?? NEWTITLE := 'condition_handler', EJECT ??

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

      VAR
        local_status: ost$status;

      pmp$log ('*** BTF - Handler condition:', ignore_status);
      osp$set_status_from_condition ('NF', condition, save_area, local_status, ignore_status);
      nap$display_message (local_status);

      abort_message.task_status := local_status;
      abort_message.filter_aborted := FALSE;

      nfp$put_async_task_message (connected_task, ^abort_message, #SIZE (abort_message), async_status);
      IF NOT async_status.normal THEN
        pmp$log ('*** BTF - Handler: put_async_task_message', ignore_status);
        nap$display_message (async_status);
      IFEND;

      retry_count := 0;
      REPEAT
        pmp$wait (250, 250);
        nfp$end_async_communication (async_status.normal, local_status);
        retry_count := retry_count + 1;
      UNTIL (local_status.normal) OR (NOT async_status.normal) OR
            (local_status.condition <> nfe$activity_pending) OR (retry_count > 100);
      IF NOT local_status.normal THEN
        pmp$log ('*** BTF - Handler: end_async_communication', ignore_status);
        nap$display_message (local_status);
      IFEND;

{ If the network connection still exists, terminate it.

      IF control_block.path.path_connected THEN
        nfp$terminate_path (control_block.application, TRUE, control_block.path, ignore_status);
      IFEND;

{ Clean up output filter variables and files.  Deleting of job-scope variables
{ is done twice to bypass an SCL anomaly that does not always delete them.

      clp$delete_variable (descriptor_packet.device_environment_variable, ignore_status);
      clp$delete_variable (descriptor_packet.device_environment_variable, ignore_status);
      clp$delete_variable (file_attributes_var, ignore_status);
      clp$delete_variable (file_attributes_var, ignore_status);
      clp$delete_variable (file_disposition_var, ignore_status);
      clp$delete_variable (file_disposition_var, ignore_status);
      clp$delete_variable (output_file_var, ignore_status);
      clp$delete_variable (output_file_var, ignore_status);

      amp$return (output, ignore_status);
      amp$return (statistics_file, ignore_status);

    PROCEND condition_handler;

?? TITLE := 'log_abnormal_condition', EJECT ??

    PROCEDURE log_abnormal_condition
      (    network_address: nat$network_address;
           station: ost$name;
           device: ost$name;
           abnormal_status: ost$status);

      VAR
        converted_string: ^string ( * ),
        converted_string_length: integer,
        ignore_status: ost$status,
        message: string (80),
        message_length: integer;

      IF (network_address.kind = nac$osi_transport_address) THEN
        PUSH converted_string: [2 * network_address.osi_transport_address.network_address_length];
        convert_sequence_to_hex_string (^network_address.osi_transport_address.network_address,
              network_address.osi_transport_address.network_address_length, converted_string,
              converted_string_length);
        STRINGREP (message, message_length, 'NETWORK_ADDRESS: ', converted_string^ (1,
              converted_string_length));
        pmp$log (message (1, message_length), ignore_status);
      ELSE
        pmp$log ('NETWORK_ADDRESS: *unknown kind*', ignore_status);
      IFEND;

      STRINGREP (message, message_length, 'STATION: ', station);
      pmp$log (message (1, message_length), ignore_status);

      STRINGREP (message, message_length, 'DEVICE: ', device);
      pmp$log (message (1, message_length), ignore_status);

      nap$display_message (abnormal_status);

    PROCEND log_abnormal_condition;

?? OLDTITLE, EJECT ??

    status.normal := TRUE;

    abort_message.kind := nfc$abnormal_child_task_abort;
    btf_completion_packet.btf_transfer_status := nfc$transfer_failed_re_q_file;
    btf_completion_packet.filter_aborted := FALSE;
    btf_completion_packet.kind := nfc$btf_file_transfer_status;
    PUSH control_block.path.network_file: [osc$max_name_size];
    control_block.path.path_connected := FALSE;
    PUSH error_descriptor;
    file_attributes_var := osc$null_name;
    file_disposition := print_and_terminate;
    file_disposition_var := osc$null_name;
    output := osc$null_name;
    output_file_contains_data := FALSE;
    output_file_var := osc$null_name;
    statistics_file := osc$null_name;
    statistics_file_contains_data := FALSE;

{ Initiate the communication link with the calling task (SCF or NTF).

    nfp$begin_asynchronous_task (program_parameters, connected_task, ignore_queue_id, status);
    IF NOT status.normal THEN
      pmp$log ('*** BTF: begin_asynchronous_task', ignore_status);
      nap$display_message (status);
      RETURN;
    IFEND;

    pmp$establish_condition_handler (block_exit_condition, ^condition_handler, error_descriptor,
          ignore_status);

{ Communicate with calling task to get the file descriptor information.

    nfp$get_async_task_message (connected_task, ^descriptor_packet, #SIZE (descriptor_packet),
          nfc$max_wait_time, transfer_count, status);
    IF NOT status.normal THEN
      pmp$log ('*** BTF: get_async_task_message', ignore_status);
      nap$display_message (status);
      nfp$end_async_communication (FALSE, local_status);
      IF NOT local_status.normal THEN
        pmp$log ('*** BTF: end_async_communication (1)', ignore_status);
        nap$display_message (local_status);
      IFEND;
      RETURN;
    ELSEIF {status.normal AND} transfer_count = 0 THEN
      osp$set_status_abnormal ('NF', nfe$bts_internal_error, '*** BTF', status);
      osp$append_status_parameter (osc$status_parameter_delimiter, 'async task message transfer_count = 0',
            status);
      nap$display_message (status);
      RETURN;
    IFEND;

{ Check the new file descriptor for the correct station and device
{ and initialize the completion packet for this file descriptor.

    CASE descriptor_packet.btf_file_descriptor.file_kind OF
    = nfc$output_file =
      selected_station := descriptor_packet.btf_file_descriptor.output_descriptor.station;
      selected_device := descriptor_packet.btf_file_descriptor.output_descriptor.device;

      copies := descriptor_packet.btf_file_descriptor.output_descriptor.copies -
            descriptor_packet.btf_file_descriptor.output_descriptor.copies_printed;
      btf_completion_packet.btf_system_file_name := descriptor_packet.btf_file_descriptor.output_descriptor.
            system_file_name;
      btf_completion_packet.copies_printed := descriptor_packet.btf_file_descriptor.output_descriptor.
            copies_printed;
      file_position := descriptor_packet.btf_file_descriptor.output_descriptor.file_position;

    = nfc$input_file =
      selected_station := descriptor_packet.btf_file_descriptor.input_descriptor.station;
      selected_device := descriptor_packet.btf_file_descriptor.input_descriptor.job_input_device.text;

      copies := 1;
      btf_completion_packet.copies_printed := 0;
      file_position := 0;
      btf_completion_packet.btf_system_file_name := descriptor_packet.btf_file_descriptor.input_descriptor.
            system_job_name;

    CASEND;

    local_file_name := descriptor_packet.ntf_local_file_name;
    ntf_local_file := (local_file_name <> osc$null_name);

{ Initialize the file transfer control block

    setup_control_block (descriptor_packet.btf_file_descriptor, control_block, device, station, status);

{ Filter output printer files.

    IF (status.normal) AND (descriptor_packet.btf_file_descriptor.file_kind = nfc$output_file) AND
          (descriptor_packet.btf_file_descriptor.output_descriptor.output_destination_usage <> jmc$ntf_usage)
          THEN
      execute_batch_output_filter (descriptor_packet, btf_completion_packet, control_block,
            file_attributes_var, file_disposition, file_disposition_var, output, output_file_contains_data,
            output_file_var, statistics_file, statistics_file_contains_data, status);
      transfer_file := (status.normal) AND ((file_disposition = print_and_hold) OR
            (file_disposition = print_and_terminate));
      IF output_file_contains_data AND transfer_file THEN
        local_file_name := output;
      IFEND;
    ELSE
      transfer_file := status.normal;
    IFEND;

{ Connect to the network address supplied by the calling task.

    IF transfer_file THEN
      connection_initiation_phase (descriptor_packet.network_address, station, device, network_file_name,
            control_block, status);
      transfer_file := status.normal;
    IFEND;

{ Transfer the file to the batch device or stream.

  /transfer_until_copy_count/
    REPEAT

      IF transfer_file THEN
        init_and_data_transfer_phase (descriptor_packet.btf_file_descriptor, local_file_name, ntf_local_file,
              control_block, status);
        btf_completion_packet.btf_task_status := control_block.state_of_transfer;
      ELSE
        btf_completion_packet.btf_task_status := status;
      IFEND;

{ File transfer completed normally if both task_status and status are normal.

      IF btf_completion_packet.btf_task_status.normal AND status.normal THEN

        IF transfer_file THEN
          btf_completion_packet.copies_printed := btf_completion_packet.copies_printed + 1;
        IFEND;

{ Update the number of copies transferred for an output descriptor.

        IF (descriptor_packet.btf_file_descriptor.file_kind = nfc$output_file) AND
              (descriptor_packet.btf_file_descriptor.output_descriptor.output_destination_usage <>
              jmc$ntf_usage) AND (transfer_file) THEN
          PUSH output_status_updates: [1 .. 1];
          output_status_updates^ [1].key := jmc$copies_printed;
          output_status_updates^ [1].copies_printed := btf_completion_packet.copies_printed;
          jmp$update_output_status (descriptor_packet.btf_file_descriptor.output_descriptor.system_file_name,
                descriptor_packet.btf_file_descriptor.output_descriptor.output_destination_usage,
                descriptor_packet.btf_file_descriptor.q_file_password, output_status_updates, ignore_status);
        IFEND;

        IF (file_disposition = hold) OR (file_disposition = print_and_hold) THEN
          btf_completion_packet.btf_transfer_status := nfc$filter_hold_file;
        ELSE
          btf_completion_packet.btf_transfer_status := nfc$transfer_complete_drop_file;
          IF (file_disposition = terminate) THEN

{ Substitute actual system supplied file name in "terminate" message.

            terminated_message (6, jmc$system_supplied_name_size) :=
                  descriptor_packet.btf_file_descriptor.output_descriptor.system_file_name;
            pmp$log (terminated_message, ignore_status);
          IFEND;
        IFEND;

{ Emit output filter statistics if any.

        IF statistics_file_contains_data THEN
          process_statistics_file (statistics_file);
        IFEND;

      ELSE { File transfer terminated abnormally

{ In the case where both btf task status and status are abnormal, the
{ task status is more important - this status will usually be set
{ based upon the state of transfer.

        IF NOT btf_completion_packet.btf_task_status.normal THEN
          CASE btf_completion_packet.btf_task_status.condition OF
          = nfe$requeue_not_eligible_file =
            btf_completion_packet.btf_transfer_status := nfc$operator_hold_file;
          = nfe$station_operator_terminate =
            btf_completion_packet.btf_transfer_status := nfc$transfer_complete_drop_file;
          ELSE { all other abnormal conditions
            log_abnormal_condition (descriptor_packet.network_address, selected_station, selected_device,
                  btf_completion_packet.btf_task_status);
            btf_completion_packet.btf_transfer_status := nfc$transfer_failed_re_q_file;
            IF (descriptor_packet.btf_file_descriptor.file_kind = nfc$output_file) AND
                  (descriptor_packet.btf_file_descriptor.output_descriptor.output_destination_usage <>
                  jmc$ntf_usage) THEN
              PUSH output_status_updates: [1 .. 1];
              output_status_updates^ [1].key := jmc$file_position;
              output_status_updates^ [1].file_position := file_position;
              jmp$update_output_status (descriptor_packet.btf_file_descriptor.output_descriptor.
                    system_file_name, descriptor_packet.btf_file_descriptor.output_descriptor.
                    output_destination_usage, descriptor_packet.btf_file_descriptor.q_file_password,
                    output_status_updates, ignore_status);
            IFEND;
          CASEND;

        ELSE { NOT status.normal

          btf_completion_packet.btf_task_status := status;
          log_abnormal_condition (descriptor_packet.network_address, selected_station, selected_device,
                btf_completion_packet.btf_task_status);
          btf_completion_packet.btf_transfer_status := nfc$transfer_failed_re_q_file;
          IF (descriptor_packet.btf_file_descriptor.file_kind = nfc$output_file) AND
                (descriptor_packet.btf_file_descriptor.output_descriptor.output_destination_usage <>
                jmc$ntf_usage) THEN
            PUSH output_status_updates: [1 .. 1];
            output_status_updates^ [1].key := jmc$file_position;
            output_status_updates^ [1].file_position := file_position;
            jmp$update_output_status (descriptor_packet.btf_file_descriptor.output_descriptor.
                  system_file_name, descriptor_packet.btf_file_descriptor.output_descriptor.
                  output_destination_usage, descriptor_packet.btf_file_descriptor.q_file_password,
                  output_status_updates, ignore_status);
          IFEND;
        IFEND;
      IFEND;

    UNTIL (btf_completion_packet.copies_printed >= copies) OR
          (NOT btf_completion_packet.btf_task_status.normal) OR (NOT transfer_file);

{ Cleanup after output filters:  delete job-scope SCL variables and delete
{ files.  Deleting of job-scope variables is done twice to bypass an SCL anomaly
{ that does not always delete them.

    clp$delete_variable (descriptor_packet.device_environment_variable, ignore_status);
    clp$delete_variable (descriptor_packet.device_environment_variable, ignore_status);
    clp$delete_variable (file_attributes_var, ignore_status);
    clp$delete_variable (file_attributes_var, ignore_status);
    clp$delete_variable (file_disposition_var, ignore_status);
    clp$delete_variable (file_disposition_var, ignore_status);
    clp$delete_variable (output_file_var, ignore_status);
    clp$delete_variable (output_file_var, ignore_status);

    amp$return (output, ignore_status);
    amp$return (statistics_file, ignore_status);

{ Send updated completion packet to calling task.

    retry_count := 0;
    REPEAT
      IF retry_count > 0 THEN
        pmp$wait (250, 250);
      IFEND;
      nfp$put_async_task_message (connected_task, ^btf_completion_packet, #SIZE (btf_completion_packet),
            async_status);
      retry_count := retry_count + 1;
    UNTIL (async_status.normal) OR (retry_count > 10);
    IF NOT async_status.normal THEN
      pmp$log ('*** BTF: put_async_task_message (message lost)', ignore_status);
      nap$display_message (async_status);
    IFEND;

{ Wait for the calling task to pick up the completion packet

    retry_count := 0;
    REPEAT
      pmp$wait (250, 250);
      nfp$end_async_communication (async_status.normal, local_status);
      retry_count := retry_count + 1;
    UNTIL (local_status.normal) OR (NOT async_status.normal) OR
          (local_status.condition <> nfe$activity_pending) OR (retry_count > 100);
    IF NOT local_status.normal THEN
      pmp$log ('*** BTF: end_async_communication (2)', ignore_status);
      nap$display_message (local_status);
    IFEND;

{ Terminate the connection if it still exists.

    IF control_block.path.path_connected THEN
      nfp$terminate_path (control_block.application, TRUE, control_block.path, ignore_status);
    IFEND;

    pmp$disestablish_cond_handler (block_exit_condition, ignore_status);

  PROCEND nfp$btf_client;
?? OLDTITLE ??

?? NEWTITLE := 'process_statistics_file', EJECT ??

{  PROCEDURE:  process_statistics_file
{
{  PURPOSE:    To parse a file which contains legible statistics definitions
{              to be emitted using sfp$emit_statistic.
{
{  DESCRIPTION: This routine parses a legible file that was created by one
{              or more site defined procedures that executed when the main
{              batch output filter was called.
{
{  INPUT PARAMETERS: The file name of the user statistic file.
{
{  OUTPUT PARAMETERS:
{              none
{
{  ALGORITHM:
{              Attempt to open the file
{              Read lines from the file
{               Check if the first token is a name
{                 Convert the name to a statistic code
{                 Check if a valid string token is present
{                 Check if one or more integer tokens are present
{                 Emit the statistic

  PROCEDURE process_statistics_file
    (    file: fst$file_reference);

    VAR
      attachment_options: ^fst$attachment_options,
      byte_address_in_file: amt$file_byte_address,
      bytes_read_from_file: amt$transfer_count,
      counter_index: integer,
      token: clt$lexical_token,
      descriptive_data: string (sfc$max_descriptive_data_size),
      descriptive_data_length: integer,
      local_status: ost$status,
      file_identifier: amt$file_identifier,
      file_position: amt$file_position,
      line_from_stat_file: string (osc$max_string_size),
      ignore_status: ost$status,
      index_into_line: clt$string_index,
      passed_counters: ^array [1 .. * ] of sft$counter,
      spaces_before_token: boolean,
      statistic_code: sft$statistic_code,
      stored_counters: ^array [1 .. sfc$max_number_of_counters] of sft$counter,
      token_options: clt$token_evaluation_options;

    PUSH attachment_options: [1 .. 1];
    attachment_options^ [1].selector := fsc$create_file;
    attachment_options^ [1].create_file := FALSE;

    fsp$open_file (file, amc$record, attachment_options, NIL, NIL, NIL, NIL, file_identifier, local_status);
    IF local_status.normal THEN
      file_position := amc$boi;
      token_options := $clt$token_evaluation_options [clc$ignore_spaces_before_token];

      amp$get_next (file_identifier, ^line_from_stat_file, osc$max_string_size, bytes_read_from_file,
            byte_address_in_file, file_position, local_status);
      IF local_status.normal THEN
        WHILE (file_position <> amc$eoi) AND local_status.normal DO
          index_into_line := 1;
          token.kind := clc$unknown_token;
          local_status.normal := TRUE;

          clp$evaluate_token (line_from_stat_file (1, bytes_read_from_file), token_options, index_into_line,
                spaces_before_token, token, local_status);
          IF local_status.normal THEN
            IF (token.kind = clc$name_token) THEN
              sfp$convert_stat_name_to_code (token.str.value (1, 31), statistic_code, local_status);
              IF local_status.normal THEN
                clp$evaluate_token (line_from_stat_file (1, bytes_read_from_file), token_options,
                      index_into_line, spaces_before_token, token, local_status);
              IFEND;
            ELSE
              osp$set_status_abnormal ('SF', sfe$invalid_statistic_name, ' ', local_status);
            IFEND;
          IFEND;

          IF local_status.normal THEN
            IF (token.kind = clc$string_token) THEN
              IF token.str.size <= sfc$max_descriptive_data_size THEN
                descriptive_data := token.str.value;
                descriptive_data_length := token.str.size;

                clp$evaluate_token (line_from_stat_file (1, bytes_read_from_file), token_options,
                      index_into_line, spaces_before_token, token, local_status);
              ELSE
                osp$set_status_abnormal ('SF', sfe$descriptive_data_size, ' ', local_status);
              IFEND;
            ELSE
              descriptive_data := '';
              descriptive_data_length := 0;
            IFEND;
          IFEND;

          IF local_status.normal THEN
            IF (token.kind = clc$signed_integer_token) OR (token.kind = clc$unsigned_integer_token) THEN
              counter_index := 0;
              ALLOCATE stored_counters;
              WHILE ((token.kind = clc$signed_integer_token) OR
                    (token.kind = clc$unsigned_integer_token)) AND local_status.normal DO
                counter_index := counter_index + 1;
                IF counter_index <= sfc$max_number_of_counters THEN
                  stored_counters^ [counter_index] := token.int.value;
                  clp$evaluate_token (line_from_stat_file (1, bytes_read_from_file), token_options,
                        index_into_line, spaces_before_token, token, local_status);
                ELSE
                  osp$set_status_abnormal ('SF', sfe$counter_array_size_range, ' ', local_status);
                IFEND;
              WHILEND;
              IF local_status.normal THEN
                ALLOCATE passed_counters: [1 .. counter_index];
                WHILE (counter_index > 0) DO
                  passed_counters^ [counter_index] := stored_counters^ [counter_index];
                  counter_index := counter_index - 1;
                WHILEND;
              IFEND;
              FREE stored_counters;
            ELSE
              passed_counters := NIL;
            IFEND;
          IFEND;

          IF local_status.normal THEN
            sfp$emit_statistic (statistic_code, descriptive_data (1, descriptive_data_length),
                  passed_counters, local_status);
            IF passed_counters <> NIL THEN
              FREE passed_counters;
            IFEND;
          IFEND;

          IF NOT local_status.normal THEN
            pmp$log ('*** BTF process_statistics_file:', ignore_status);
            pmp$log (line_from_stat_file (1, bytes_read_from_file), ignore_status);
            nfp$format_message_to_job_log (local_status);
          IFEND;

          amp$get_next (file_identifier, ^line_from_stat_file, osc$max_string_size, bytes_read_from_file,
                byte_address_in_file, file_position, local_status);
        WHILEND;
      ELSE
        nfp$format_message_to_job_log (local_status);
      IFEND;
    ELSE
      nfp$format_message_to_job_log (local_status);
    IFEND;

  PROCEND process_statistics_file;
?? OLDTITLE ??

?? TITLE := 'setup_control_block', EJECT ??

{ PURPOSE:  Initialize the protocol parameters in the control block.

  PROCEDURE setup_control_block
    (    application_file: nft$application_file_descriptor;
     VAR control_block: nft$control_block;
     VAR device: ost$name;
     VAR station: ost$name;
     VAR status: ost$status);

    CONST
      block_size = 1452,
      catenet_value = ',CATENET',
      page_width_size = 3;

    TYPE
      date_and_time_format = (segmented, continuous),
      date_and_time_type = record
        case date_and_time_format of
        = segmented =
          month: string (2),
          slash_1: string (1),
          day: string (2),
          slash_2: string (1),
          year: string (2),
          blank_1: string (1),
          hour: string (2),
          colon_1: string (1),
          minute: string (2),
          colon_2: string (1),
          second: string (2),
        = continuous =
          date_and_time_string: string (2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2),
        casend,
      recend;

    VAR
      banner_date_and_time: date_and_time_type,
      echo_text: ^nft$parameter_29_definition,
      facilities: nft$parameter_03_value_set,
      family_name: ost$name,
      ignore_status: ost$status,
      page_width: string (page_width_size),
      protocol_in_use:  nft$parameter_00_values,
      queued_date_and_time: ost$date_time,
      save_network_connection_info: nft$network_connection,
      start_text_position: integer,
      system_routing_text: jmt$system_routing_text,
      system_routing_text_string: string (nfc$p32_max_param_length_b101),
      text_length: integer,
      transfer_lid_string: nft$parameter_25_definition,
      user_name: ost$name;


    status.normal := TRUE;

    save_network_connection_info.path_connected := FALSE;
    protocol_in_use := nfc$p00_b101;
    facilities := $nft$parameter_03_value_set [nfc$temporary_hold, nfc$ss_ack_required];

{ If a network connection exists, save this path information and replace this into
{ the control block after initialization of control block fields.

    IF control_block.path.path_connected THEN
      save_network_connection_info := control_block.path;
    IFEND;

{ Initialize control block with defaults.

    nfp$initialize_control_block (nfc$application_btf, nfc$p31_ascii_c8, facilities, facilities, facilities,
          protocol_in_use, nfc$take, ^parameter_rules, control_block);

{ Initialize control block with protocol defaults.

    control_block.data_block_size := block_size;
    control_block.time_out := nfc$timeout_limit;
    control_block.local_host_type := nfc$p22_nos_ve;

{ Initialize control block with file information.

    control_block.queue_file_password := application_file.q_file_password;

    CASE application_file.file_kind OF

    = nfc$output_file =

      control_block.banner_date_and_time.size := 0;
      control_block.banner_date_and_time.value := ' ';

      control_block.banner_routing_text.size := nfp$string_length
            (application_file.output_descriptor.routing_banner);
      control_block.banner_routing_text.value := application_file.output_descriptor.routing_banner;

      IF application_file.output_descriptor.data_mode = jmc$transparent_data THEN
        control_block.data_declaration := nfc$p31_undef_unstructured_uu;
      ELSE
        control_block.data_declaration := nfc$p31_ascii_c8;
      IFEND;

      control_block.destination_usage := application_file.output_descriptor.output_destination_usage;
      control_block.disposition_code := nfc$p17_line_printer;
      control_block.file_position := application_file.output_descriptor.file_position;
      control_block.file_size := application_file.output_descriptor.file_size;
      control_block.installation_banner_message.size := nfp$string_length
            (application_file.output_descriptor.site_information);
      control_block.installation_banner_message.value := application_file.output_descriptor.site_information;

      control_block.send_file_name.size := nfp$string_length
            (application_file.output_descriptor.system_file_name);
      control_block.send_file_name.value := application_file.output_descriptor.system_file_name;
      control_block.send_job_name.size  := nfp$string_length
            (application_file.output_descriptor.user_job_name);
      control_block.send_job_name.value := application_file.output_descriptor.user_job_name;

      control_block.user_banner_message.size := nfp$string_length
            (application_file.output_descriptor.comment_banner);
      control_block.user_banner_message.value := application_file.output_descriptor.comment_banner;

      control_block.user_file_name.size := nfp$string_length
            (application_file.output_descriptor.user_file_name);
      control_block.user_file_name.value := application_file.output_descriptor.user_file_name;

      control_block.vertical_print_density := application_file.output_descriptor.vertical_print_density;
      control_block.vfu_load_procedure.size := nfp$string_length
            (application_file.output_descriptor.vfu_load_procedure);
      control_block.vfu_load_procedure.value := application_file.output_descriptor.vfu_load_procedure;

      device := application_file.output_descriptor.device;
      IF application_file.output_descriptor.control_family <> osc$null_name THEN
        family_name := application_file.output_descriptor.control_family;
      ELSEIF application_file.output_descriptor.login_family <> osc$null_name THEN
        family_name := application_file.output_descriptor.login_family;
      ELSE
        family_name := osc$null_name;
      IFEND;
      station := application_file.output_descriptor.station;
      system_routing_text := application_file.output_descriptor.system_routing_text;
      IF application_file.output_descriptor.control_user <> osc$null_name THEN
        user_name := application_file.output_descriptor.control_user;
      ELSEIF application_file.output_descriptor.login_user <> osc$null_name THEN
        user_name := application_file.output_descriptor.login_user;
      ELSE
        user_name := application_file.output_descriptor.user_job_name;
      IFEND;

      IF application_file.output_descriptor.output_destination_usage <> jmc$ntf_usage THEN

{ Set page_width in send_echo_text

        ALLOCATE echo_text;
        IF echo_text = NIL THEN
          osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error, 'ALLOCATE for echo_text failed',
                status);
          RETURN;
        IFEND;
        clp$convert_integer_to_rjstring (application_file.output_descriptor.page_width, 10, FALSE, '0',
              page_width, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        echo_text^.size := page_width_size;
        echo_text^.value := page_width;
        echo_text^.link := NIL;
        control_block.send_echo_text.first_text := echo_text;
        control_block.send_echo_text.last_text := echo_text;
      IFEND;

    = nfc$input_file =

      control_block.banner_date_and_time.size := 0;
      control_block.banner_date_and_time.value := ' ';

      IF application_file.input_descriptor.data_mode = jmc$transparent_data THEN
        control_block.data_declaration := nfc$p31_undef_unstructured_uu;
      ELSE
        control_block.data_declaration := nfc$p31_ascii_c8;
      IFEND;

      control_block.destination_usage := application_file.input_descriptor.job_destination_usage;
      control_block.disposition_code := nfc$p17_input_return;
      control_block.file_position := 0;
      control_block.file_size := application_file.input_descriptor.job_size;

      control_block.send_file_name.size := nfp$string_length
            (application_file.input_descriptor.system_job_name);
      control_block.send_file_name.value := application_file.input_descriptor.system_job_name;
      control_block.send_job_name.size  := nfp$string_length
            (application_file.input_descriptor.user_job_name);
      control_block.send_job_name.value := application_file.input_descriptor.user_job_name;

      control_block.user_file_name.size := nfp$string_length
            (application_file.input_descriptor.user_job_name);
      control_block.user_file_name.value := application_file.input_descriptor.user_job_name;

      control_block.vertical_print_density := jmc$vertical_print_density_none;
      control_block.vfu_load_procedure.size := 0;
      control_block.vfu_load_procedure.value := ' ';

      device := application_file.input_descriptor.job_input_device.text;
      family_name := application_file.input_descriptor.login_family;
      station := application_file.input_descriptor.station;
      system_routing_text := application_file.input_descriptor.system_routing_text;
      user_name := application_file.input_descriptor.login_user;

    ELSE
      osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error,
            'invalid application file descriptor', status);
      RETURN;
    CASEND;

{  Build transfer lid text.

    transfer_lid_string := ' ';
    start_text_position := 1;
    text_length := nfp$string_length (station);
    transfer_lid_string (start_text_position, text_length) := station;
    start_text_position := start_text_position + text_length;
    transfer_lid_string (start_text_position, * ) := catenet_value;

    control_block.transfer_lid_length := nfp$string_length (transfer_lid_string);
    control_block.transfer_lid := transfer_lid_string;

{  Build system routing text if there currently is no text in the descriptor
{  or if the current routing text starts with 'CYB'.  Otherwise, pass down
{  original routing text.

    IF (system_routing_text.size = 0) OR ((system_routing_text.size >= nfc$p32_min_param_length_b101) AND
          (system_routing_text.parameters (1, 3) = nfc$p32_cyber_id)) THEN
      system_routing_text_string := 'UID,';
      start_text_position := 5;
      IF user_name <> osc$null_name THEN
        text_length := nfp$string_length (user_name);
      ELSE
        text_length := 1;
      IFEND;
      system_routing_text_string (start_text_position, text_length) := user_name;
      start_text_position := start_text_position + text_length;
      system_routing_text_string (start_text_position, 1) := ',';
      start_text_position := start_text_position + 1;
      IF family_name <> osc$null_name THEN
        text_length := nfp$string_length (family_name);
      ELSE
        text_length := 1;
      IFEND;
      system_routing_text_string (start_text_position, text_length) := family_name;
      start_text_position := start_text_position + text_length;
      system_routing_text_string (start_text_position, * ) := catenet_value;

      control_block.send_systems_routing_text.size := nfp$string_length (system_routing_text_string);
      control_block.send_systems_routing_text.parameters := system_routing_text_string;
    IFEND;

{  Build banner date and time text.

    CASE application_file.file_kind OF
    = nfc$output_file =
      queued_date_and_time := application_file.output_descriptor.output_submission_time;
    = nfc$input_file =
      queued_date_and_time := application_file.input_descriptor.job_submission_time;
    ELSE
      osp$set_status_abnormal (nfc$status_id, nfe$bts_internal_error,
            'invalid application file descriptor', status);
      RETURN;
    CASEND;

    banner_date_and_time.blank_1 := ' ';
    banner_date_and_time.colon_1 := ':';
    banner_date_and_time.colon_2 := ':';
    banner_date_and_time.slash_1 := '/';
    banner_date_and_time.slash_2 := '/';

    IF (queued_date_and_time.year > 99) THEN
      queued_date_and_time.year := queued_date_and_time.year - 100;
    IFEND;

    clp$convert_integer_to_rjstring (queued_date_and_time.year, 10, FALSE, '0',
          banner_date_and_time.year, ignore_status);
    clp$convert_integer_to_rjstring (queued_date_and_time.month, 10, FALSE, '0',
          banner_date_and_time.month, ignore_status);
    clp$convert_integer_to_rjstring (queued_date_and_time.day, 10, FALSE, '0',
          banner_date_and_time.day, ignore_status);
    clp$convert_integer_to_rjstring (queued_date_and_time.hour, 10, FALSE, '0',
          banner_date_and_time.hour, ignore_status);
    clp$convert_integer_to_rjstring (queued_date_and_time.minute, 10, FALSE, '0',
          banner_date_and_time.minute, ignore_status);
    clp$convert_integer_to_rjstring (queued_date_and_time.second, 10, FALSE, '0',
          banner_date_and_time.second, ignore_status);
    control_block.banner_date_and_time.value := banner_date_and_time.date_and_time_string;
    control_block.banner_date_and_time.size := #SIZE (date_and_time_type);

{ If network connection did exist, then restore network connection path information.

    IF save_network_connection_info.path_connected THEN
      control_block.path := save_network_connection_info;
    IFEND;

  PROCEND setup_control_block;
MODEND nfm$btf_client;
