?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE job management timesharing signal handler module' ??
MODULE jmm$timesharing_signal_handler;

{ Purpose: This module contains the signal handler for the timesharing application
{          signals.  It also contains the necessary support interfaces for the condition
{          handling of the interactive conditions associated with the timesharing signals.

{ Notes: The path of a timesharing (interactive) condition is sort of awkward.  The path
{        is as follows (ignoring block exit processing):

{        JMP$TIMESHARING_SIGNAL_HANDLER gets control via a signal from networks.
{          pmp$disable_ts_io_in_tasks
{
{          pmp$begin_timesharing_condition
{          pmp$enable_timesharing_io
{
{          pmp$dispose_interactive_cond

{        PMP$DISPOSE_INTERACTIVE_COND does the following:
{          jmp$begin_timesharing_handler
{
{          find_the_users_handler
{          if found then
{            execute_it
{          else                            / if psa <> nil then
{            post_ring_crossing_condition <    jmp$begin_timesharing_handler
{          ifend                           \ ifend
{
{          jmp$end_timesharing_handler

{        PROCESS_DELAYED_CONDITION does the following:
{          jmp$begin_timesharing_handler
{
{          find_the_users_handler
{          if found then
{            execute_it
{          else                            / if psa <> nil then
{            post_ring_crossing_condition <    jmp$begin_timesharing_handler
{          ifend                           \ ifend
{
{          jmp$end_timesharing_handler
{
{          jmp$end_timesharing_handler (this offsets the call in pmp$dispose_interactive_cond)

{        JMP$BEGIN_TIMESHARING_HANDLER
{          pmp$begin_timesharing_handler

{        JMP$END_TIMESHARING_HANDLER
{          pmp$end_timesharing_handler
{
{          if pmp$zero_ts_conditions_in_task then
{            pmp$enable_ts_io_in_tasks
{          ifend

{        1.  In order to do I/O on the connection, a task's pmp$ts_task_io_enabled request must
{            return a value of true.  NOTE: the job monitor task can always do I/O on the connection.
{        2.  A count of the number of condition handlers that have been invoked in a task is kept.
{            When this count is zero, it indicates that all condition handlers have been processed to
{            completion in the task.  This implies that the task is no longer processing any conditions.
{            This being the case, we call pmp$enable_ts_io_in_tasks to re-enable io in the appropriate
{            tasks.
{        3.  User interrupts (user status commands) are processed within the job monitor task.


?? NEWTITLE := 'Global Declarations Referenced by this Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc amt$local_file_name
*copyc ave$validation_interface_errors
*copyc clc$standard_file_names
*copyc ifc$interrupt
*copyc ifc$interrupt_timesharing_io
*copyc ife$error_codes
*copyc ift$condition_codes
*copyc iiv$connection_desc_ptr
*copyc jmc$job_management_id
*copyc jmc$submit_detached_jobs
*copyc jme$cannot_detach_xterm_job
*copyc jme$invalid_paired_connection
*copyc jme$multiple_detached_jobs
*copyc jme$transaction_job_disconnect
*copyc jme$unlimited_timeout_message
*copyc jme$queued_file_conditions
*copyc jmt$paired_connection_data
*copyc jmt$service_data
*copyc jmt$submit_job_variations
*copyc jmt$timesharing_signal
*copyc nae$application_interfaces
*copyc osc$timesharing
*copyc osc$timesharing_terminal_file
*copyc oss$job_paged_literal
*copyc oss$task_shared
*copyc ost$global_task_id
*copyc ost$status
*copyc pmt$binary_mainframe_id
*copyc pmt$condition
*copyc pmt$signal
*copyc sft$audit_information
*copyc syv$nosve_job_template
*copyc syv$clone_enabled
*copyc syv$job_initialization_complete
*copyc tmc$signal_identifiers
*copyc tmc$wait_times
*copyc avc$accounting_statistics
?? POP ??
*copyc amp$flush
*copyc amp$put_next
*copyc avp$get_capability
*copyc avp$security_option_active
*copyc clp$find_current_job_synch_task
*copyc clp$get_processing_phase
*copyc clp$get_system_file_id
*copyc clp$include_command
*copyc clp$put_job_output
*copyc fmp$disconnect_for_clone
*copyc fmp$create_network_file
*copyc fsp$close_file
*copyc fsp$open_file
*copyc ifp$disconnect
*copyc ifp$get_terminal_attributes
*copyc ifp$change_terminal_attributes
*copyc ifp$reconnect
*copyc iip$interrupt_timesharing_io
*copyc iip$restore_term_conn_atributes
*copyc iip$set_terminal_name
*copyc iip$st_clone_connection
*copyc iip$vtp_create_paired_connect
*copyc iip$vtp_del_paired_con_first
*copyc iip$vtp_delete_paired_connect
*copyc i#move
*copyc jmp$determine_name_kind
*copyc jmp$display_job_status
*copyc jmp$emit_communication_stat
*copyc jmp$get_encrypted_password
*copyc jmp$get_job_attributes
*copyc jmp$get_job_internal_info
*copyc jmp$get_job_status
*copyc jmp$get_result_size
*copyc jmp$is_dual_state_job
*copyc jmp$is_xterm_job
*copyc jmp$logout
*copyc jmp$set_job_input_device
*copyc jmp$set_job_mode
*copyc jmp$submit_job
*copyc jmp$system_job
*copyc jmp$terminate_job
*copyc jmp$update_display_message
*copyc jmp$validate_user
*copyc lgp$display_log
*copyc nac$null_connection_id
*copyc nap$acquire_connection
*copyc nap$clone_connection
*copyc nap$attach_server_application
*copyc nap$cancel_switch_offer
*copyc nap$change_attributes
*copyc nap$detach_server_application
*copyc nap$get_attributes
*copyc nap$get_connect_data
*copyc nap$parse_accounting_data
*copyc nap$se_synchronize_confirm
*copyc nap$se_clear_request
*copyc nlp$accept_switch_offer
*copyc nlp$offer_connection_switch
*copyc nlp$record_nominal_disconnect
*copyc nlp$register_nominal_connection
*copyc nlp$simulate_connection_broken
*copyc nlp$unsimulate_connection_broke
*copyc ofp$display_status_message
*copyc osp$append_status_parameter
*copyc osp$disestablish_cond_handler
*copyc osp$establish_block_exit_hndlr
*copyc osp$establish_condition_handler
*copyc osp$format_message
*copyc osp$generate_log_message
*copyc osp$i_await_activity
*copyc osp$set_status_abnormal
*copyc osp$set_status_condition
*copyc osp$system_error
*copyc osp$verify_system_privilege
*copyc pmp$begin_timesharing_condition
*copyc pmp$begin_timesharing_handler
*copyc pmp$cause_condition
*copyc pmp$compute_date_time
*copyc pmp$continue_to_cause
*copyc pmp$convert_binary_mainframe_id
*copyc pmp$convert_mainframe_to_binary
*copyc pmp$disable_ts_io_in_tasks
*copyc pmp$display_active_tasks
*copyc pmp$dispose_interactive_cond
*copyc pmp$enable_ts_io_in_tasks
*copyc pmp$enable_timesharing_io
*copyc pmp$end_timesharing_handler
*copyc pmp$establish_condition_handler
*copyc pmp$exit
*copyc pmp$format_compact_date
*copyc pmp$format_compact_time
*copyc pmp$get_compact_date_time
*copyc pmp$get_executing_task_gtid
*copyc pmp$get_global_task_id
*copyc pmp$get_job_mode
*copyc pmp$get_job_names
*copyc pmp$get_mainframe_id
*copyc pmp$get_pseudo_mainframe_id
*copyc pmp$get_user_identification
*copyc pmp$log
*copyc pmp$log_ascii
*copyc pmp$long_term_wait
*copyc pmp$send_signal
*copyc pmp$signal_all_child_tasks
*copyc pmp$ts_task_io_enabled
*copyc pmp$zero_ts_conditions_in_task
*copyc qfp$set_terminal_name
*copyc rmp$request_terminal
*copyc sfp$emit_audit_statistic
*copyc sfp$emit_statistic
*copyc jmv$cluster_attach_job_enabled
*copyc jmv$jcb
*copyc jmv$job_attributes
*copyc jmv$kjl_p
*copyc jmv$kjlx_p
*copyc jmv$system_job_ssn
*copyc jmv$terminal_io_disabled
*copyc pmv$task_execution_phase
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by this Module', EJECT ??

  CONST
    connection_switch_timeout = 120000, { in milliseconds
    pause_break_char = '1';

  VAR
    jmv$job_timed_out: [STATIC, XDCL, oss$task_shared] boolean := FALSE,
    jmv$timesharing_job: [STATIC, XDCL, #GATE, oss$task_shared] boolean := FALSE,
    jmv$ts_interactive_condition: [STATIC, READ, oss$job_paged_literal] pmt$condition :=
          [pmc$condition_combination, $pmt$condition_combination [ifc$interactive_condition]],
    jmv$ts_disconnect_time: [STATIC, XDCL, oss$task_shared] integer := 0,
    jmv$ts_disconnect_time_left: [STATIC, XDCL, oss$task_shared] integer := 0,
    jmv$interactive_conds_disabled: [STATIC, XDCL, oss$task_shared] boolean := FALSE,
    jmv$ts_job_disconnected: [STATIC, XDCL, #GATE, oss$task_shared] boolean := FALSE,
    jmv$initialized_as_disconnected: [STATIC, XDCL, #GATE, oss$task_shared] boolean := FALSE,
    jmv$connection_acquired: [STATIC, XDCL, #GATE, oss$task_shared] boolean := TRUE,
    jmv$user_breaks_enabled: [STATIC, XDCL, #GATE, oss$task_shared] boolean := FALSE,
    jmv$xterm_job: [STATIC, XDCL, #GATE, oss$task_shared] boolean := FALSE;

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

  PROCEDURE log_message
    (    message: string ( * ));

    VAR
      local_status: ost$status;

    pmp$log (message, local_status);
  PROCEND log_message;
?? OLDTITLE ??
?? NEWTITLE := 'log_status', EJECT ??

  PROCEDURE log_status
    (    error_status: ost$status);

    VAR
      local_status: ost$status;

    osp$generate_log_message ($pmt$ascii_logset [pmc$job_log], error_status, local_status);
  PROCEND log_status;
?? OLDTITLE ??
?? NEWTITLE := 'log_unexpected_message', EJECT ??

  PROCEDURE log_unexpected_message
    (    message: string ( * ));

    VAR
      local_status: ost$status;

    pmp$log_ascii (message, $pmt$ascii_logset [pmc$system_log, pmc$job_log], pmc$msg_origin_system,
          local_status);
  PROCEND log_unexpected_message;
?? OLDTITLE ??
?? NEWTITLE := 'log_unexpected_status', EJECT ??

  PROCEDURE log_unexpected_status
    (    error_status: ost$status);

    VAR
      local_status: ost$status;

    osp$generate_log_message ($pmt$ascii_logset [pmc$system_log, pmc$job_log], error_status, local_status);
  PROCEND log_unexpected_status;
?? OLDTITLE ??
?? NEWTITLE := 'output_message', EJECT ??

  PROCEDURE output_message
    (    message: string ( * ));

    VAR
      local_status: ost$status;

    clp$put_job_output (message, local_status);
  PROCEND output_message;
?? OLDTITLE ??
?? NEWTITLE := 'put_and_flush_output', EJECT ??

  PROCEDURE put_and_flush_output
    (    text: string ( * );
     VAR status: ost$status);

    VAR
      file_id: amt$file_identifier,
      ignore_byte_address: amt$file_byte_address;

    clp$get_system_file_id (clc$job_output, file_id, status);
    IF status.normal THEN
      amp$put_next (file_id, ^text, STRLENGTH (text), ignore_byte_address, status);
      IF status.normal THEN
        amp$flush (file_id, osc$nowait, status);
      IFEND;
    IFEND;

  PROCEND put_and_flush_output;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$enable_user_breaks', EJECT ??
*copy jmh$enable_user_breaks

  PROCEDURE [XDCL, #GATE] jmp$enable_user_breaks;

    osp$verify_system_privilege;
    jmv$user_breaks_enabled := TRUE;

  PROCEND jmp$enable_user_breaks;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$disable_user_breaks', EJECT ??
*copy jmh$disable_user_breaks

  PROCEDURE [XDCL] jmp$disable_user_breaks;

    jmv$user_breaks_enabled := FALSE;

  PROCEND jmp$disable_user_breaks;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$attach_timesharing_job', EJECT ??
*copy jmh$attach_timesharing_job

  PROCEDURE [XDCL, #GATE] jmp$attach_timesharing_job
    (    job_name: string ( * <= osc$max_name_size);
     VAR status: ost$status);

    VAR
      binary_mainframe_id: pmt$binary_mainframe_id,
      current_mainframe_id: pmt$mainframe_id,
      job_status_options_p: ^jmt$job_status_options,
      job_status_results_keys_p: ^jmt$results_keys,
      job_status_results_p: ^jmt$job_status_results,
      job_status_results_seq_p: ^jmt$work_area,
      job_status_count: jmt$job_status_count,
      user_identification: ost$user_identification,
      job_internal_info: jmt$job_internal_information,
      job_mode: jmt$job_mode,
      size_of_sequence: ost$segment_length,
      timesharing_signal: jmt$timesharing_signal;

    osp$verify_system_privilege;
    status.normal := TRUE;

    pmp$get_job_mode (job_mode, status);
    IF (NOT status.normal) OR (job_mode <> jmc$interactive_connected) THEN
      RETURN;
    IFEND;

    pmp$get_user_identification (user_identification, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    PUSH job_status_options_p: [1 .. 6];
    job_status_options_p^ [1].key := jmc$job_mode_set;
    job_status_options_p^ [1].job_mode_set := $jmt$job_mode_set
          [jmc$interactive_cmnd_disconnect, jmc$interactive_line_disconnect, jmc$interactive_sys_disconnect];
    job_status_options_p^ [3].key := jmc$login_user;
    job_status_options_p^ [3].login_user := user_identification.user;
    job_status_options_p^ [4].key := jmc$login_family;
    job_status_options_p^ [4].login_family := user_identification.family;
    job_status_options_p^ [5].key := jmc$job_state_set;
    job_status_options_p^ [5].job_state_set := $jmt$job_state_set [jmc$initiated_job];
    job_status_options_p^ [6].key := jmc$continue_request_to_servers;
    job_status_options_p^ [6].continue_request_to_servers := jmv$cluster_attach_job_enabled;

    IF job_name = osc$null_name THEN
      job_status_options_p^ [2].key := jmc$null_attribute;
    ELSE
      job_status_options_p^ [2].key := jmc$name_list;
      PUSH job_status_options_p^ [2].name_list: [1 .. 1];

      jmp$determine_name_kind (job_name, job_status_options_p^ [2].name_list^ [1], status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;

    PUSH job_status_results_keys_p: [1 .. 2];
    job_status_results_keys_p^ [1] := jmc$system_job_name;
    job_status_results_keys_p^ [2] := jmc$client_mainframe_id;
    jmp$get_result_size ({number_of_jobs} 1, #SEQ (job_status_results_keys_p^), size_of_sequence);
    PUSH job_status_results_seq_p: [[REP size_of_sequence OF cell]];

    jmp$get_job_status (job_status_options_p, job_status_results_keys_p, job_status_results_seq_p,
          job_status_results_p, job_status_count, status);
    IF NOT status.normal THEN
      IF status.condition = jme$work_area_too_small THEN
        osp$set_status_condition (jme$multiple_detached_jobs, status);
      ELSEIF status.condition = jme$no_jobs_were_found THEN
        osp$set_status_abnormal ('JM', jme$name_not_found, job_name, status);
      IFEND;
      RETURN;
    IFEND;

{ Check to see if the job is running on the current mainframe.

    pmp$get_mainframe_id (current_mainframe_id, {ignore} status);
    IF current_mainframe_id = job_status_results_p^ [1]^ [2].client_mainframe_id THEN

      jmp$get_job_internal_info (job_status_results_p^ [1]^ [1].system_job_name, job_internal_info, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

{ Check to see if the job originated from a compatible network -

      IF job_internal_info.timesharing_job <> jmv$timesharing_job THEN
        osp$set_status_abnormal ('JM', jme$incompatible_network_origin, job_name, status);
        RETURN;
      IFEND;
    ELSE
      job_internal_info.jmtr_global_taskid.index := 0;
      job_internal_info.jmtr_global_taskid.seqno := 0;
    IFEND;

{ Ensure that the screen is cleared if the request is issued from
{ within a screen mode application.  Writing to the terminal using
{ a "line mode" instance of open causes this via a "context switch".
{ (If we're in "line mode", this has no effect.

    put_and_flush_output ('', status);
    status.normal := TRUE {don't care if it didn't work} ;


    IF jmv$timesharing_job THEN

{ Simulate the breaking of the connection

      nlp$simulate_connection_broken (osc$timesharing_terminal_file, status);
      IF NOT status.normal THEN
        log_status (status);
        RETURN;
      IFEND;

{ Signal the job monitor task to disconnect

      timesharing_signal.signal_id := jmc$timesharing_signal_id;
      timesharing_signal.signal_contents.signal_kind := jmc$timesharing_disconnect;
      timesharing_signal.signal_contents.disconnect.disconnect_reason := jmc$ts_attach_job;
      timesharing_signal.signal_contents.disconnect.target_job_global_task_id :=
            job_internal_info.jmtr_global_taskid;
      timesharing_signal.signal_contents.disconnect.target_job_system_supplied_name :=
            job_status_results_p^ [1]^ [1].system_job_name;
      pmp$convert_mainframe_to_binary (job_status_results_p^ [1]^ [2].client_mainframe_id,
            binary_mainframe_id, {ignore} status);
      timesharing_signal.signal_contents.disconnect.target_job_mainframe_id := binary_mainframe_id;

      pmp$send_signal (jmv$jcb.job_monitor_id, timesharing_signal.signal, status);
    ELSE

      IF current_mainframe_id = job_status_results_p^ [1]^ [2].client_mainframe_id THEN
        ifp$reconnect (job_internal_info.jmtr_global_taskid, status);
      ELSE
        osp$set_status_abnormal (jmc$job_management_id, jme$incompatible_network_origin, job_name, status);
        RETURN;
      IFEND;
    IFEND;
    IF NOT status.normal THEN
      log_unexpected_status (status);
      output_message ('The attempt to attach a job failed - check the job log for details.');
    IFEND;
  PROCEND jmp$attach_timesharing_job;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$begin_timesharing_handler', EJECT ??
*copy jmh$begin_timesharing_handler

  PROCEDURE [XDCL, #GATE] jmp$begin_timesharing_handler
    (    condition: ift$interactive_condition);

    osp$verify_system_privilege;
    IF jmp$system_job () OR (condition = ifc$interrupt) THEN
      RETURN;
    IFEND;

{ Another handler has become active or a delayed condition has been posted.

    pmp$begin_timesharing_handler;
  PROCEND jmp$begin_timesharing_handler;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$cluster_attach_job_enabled: boolean', EJECT ??

  FUNCTION [XDCL, #GATE] jmp$cluster_attach_job_enabled: boolean;

    jmp$cluster_attach_job_enabled := jmv$cluster_attach_job_enabled;
  FUNCEND jmp$cluster_attach_job_enabled;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$detach_timesharing_job', EJECT ??
*copy jmh$detach_timesharing_job

  PROCEDURE [XDCL, #GATE] jmp$detach_timesharing_job
    (VAR status: ost$status);

    VAR
      job_mode: jmt$job_mode,
      timesharing_signal: jmt$timesharing_signal;

    osp$verify_system_privilege;
    status.normal := TRUE;

    pmp$get_job_mode (job_mode, status);
    IF (NOT status.normal) OR (job_mode <> jmc$interactive_connected) THEN
      RETURN;
    IFEND;

    IF jmv$timesharing_job THEN

{ Simulate the connection as being broken

      nlp$simulate_connection_broken (osc$timesharing_terminal_file, status);
      IF NOT status.normal THEN
        log_status (status);
        RETURN;
      IFEND;

{ Signal the job_monitor task to disconnect

      timesharing_signal.signal_id := jmc$timesharing_signal_id;
      timesharing_signal.signal_contents.signal_kind := jmc$timesharing_disconnect;
      timesharing_signal.signal_contents.disconnect.disconnect_reason := jmc$ts_detach_job;

      pmp$send_signal (jmv$jcb.job_monitor_id, timesharing_signal.signal, status);

    ELSEIF jmp$is_dual_state_job () THEN
      ifp$disconnect (status);
    ELSE { This is an xterm job.
      osp$set_status_abnormal ('JM', jme$cannot_detach_xterm_job, '', status);
      RETURN;
    IFEND;
    IF NOT status.normal THEN
      log_unexpected_status (status);
      output_message ('The attempt to detach the current job failed - check the job log for details.');
    IFEND;
  PROCEND jmp$detach_timesharing_job;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$end_timesharing_handler', EJECT ??
*copy jmh$end_timesharing_handler

  PROCEDURE [XDCL, #GATE] jmp$end_timesharing_handler
    (    condition: ift$interactive_condition);

    VAR
      timesharing_signal: jmt$timesharing_signal,
      local_status: ost$status;

    osp$verify_system_privilege;
    IF jmp$system_job () OR (condition = ifc$interrupt) THEN
      RETURN;
    IFEND;
    local_status.normal := TRUE;

{ Another handler has be completed or a delayed condition has been processed.

    pmp$end_timesharing_handler;

{ Have all condition handlers in the task been completed?

    IF pmp$zero_ts_conditions_in_task () THEN

{ All conditions in this task have been processed.  Re-enable IO in the appropriate tasks

      pmp$enable_ts_io_in_tasks;

{ Give all tasks in the job a push to get them started doing IO again.

      timesharing_signal.signal_id := jmc$timesharing_signal_id;
      timesharing_signal.signal_contents.signal_kind := jmc$timesharing_restart_tasks;
      timesharing_signal.signal_contents.restart_tasks := jmc$ts_restart_child_tasks;
      pmp$send_signal (jmv$jcb.job_monitor_id, timesharing_signal.signal, local_status);
      IF NOT local_status.normal THEN
        log_unexpected_status (local_status);
      IFEND;
    IFEND;
  PROCEND jmp$end_timesharing_handler;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$generate_timesharing_title', EJECT ??
*copy jmh$generate_timesharing_title

  PROCEDURE [XDCL] jmp$generate_timesharing_title
    (    binary_mainframe_id: pmt$binary_mainframe_id;
     VAR timesharing_title: ost$name);

    CONST
      null_timesharing_title = '0000_0000$OSA$TIMESHARING';

    VAR
      local_status: ost$status,
      mainframe_id: pmt$mainframe_id;

    local_status.normal := TRUE;
    timesharing_title := null_timesharing_title;

    pmp$convert_binary_mainframe_id (binary_mainframe_id, mainframe_id, local_status);
    IF local_status.normal THEN
      timesharing_title (1, pmc$processor_model_number_size) :=
            mainframe_id (9, pmc$processor_model_number_size);
      timesharing_title (6, pmc$processor_serial_num_size) :=
            mainframe_id (14, pmc$processor_serial_num_size);
    IFEND;
  PROCEND jmp$generate_timesharing_title;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$handle_ts_io_req_failure', EJECT ??

  PROCEDURE [XDCL] jmp$handle_ts_io_req_failure
    (VAR status: ost$status);

    VAR
      executing_gtid: ost$global_task_id,
      established_handler: pmt$established_handler,
      ignore_status: ost$status,
      job_monitor_task: boolean;

?? NEWTITLE := 'handle_condition', EJECT ??

    PROCEDURE handle_condition
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           stack_frame_save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        local_status: ost$status;

      jmv$ts_disconnect_time_left := 0;
      pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);

      CASE condition.interactive_condition OF
      = ifc$pause_break =
        osp$set_status_condition (ife$pause_break_received, status);

      = ifc$terminate_break =
        osp$set_status_condition (ife$terminate_break_received, status);

      = ifc$terminal_connection_broken =
        osp$set_status_condition (ife$connection_break_disconnect, status);

      = ifc$job_reconnect =
        osp$set_status_condition (ife$terminal_reconnected_to_job, status);

      ELSE
        osp$set_status_abnormal (ifc$interactive_facility_id, 0, 'unknown interactive condition encountered.',
              status);
      CASEND;

      EXIT jmp$handle_ts_io_req_failure;
    PROCEND handle_condition;

?? OLDTITLE, EJECT ??

    status.normal := TRUE;
    ignore_status.normal := TRUE;

{ Check to see if the job is going through termination

    IF (jmv$kjl_p^ [jmv$jcb.job_id].entry_kind = jmc$kjl_terminated_entry) OR jmv$terminal_io_disabled THEN
      osp$set_status_condition (jme$job_is_in_termination, status);
      RETURN;
    IFEND;

{ Check to see if the task is going through termination

    IF (pmv$task_execution_phase > pmc$task_executing) THEN
      osp$set_status_condition (jme$task_is_in_termination, status);
      RETURN;
    IFEND;

{ Check to see if we are a transaction job that has interactive conditions disabled.

    IF jmv$initialized_as_disconnected AND jmv$interactive_conds_disabled THEN
      osp$set_status_condition (jme$transaction_job_disconnect, status);
      RETURN;
    IFEND;

{ Cause the interactive condition to pull us out if any io operations are pending.

    pmp$cause_condition (ifc$interrupt_timesharing_io, NIL, ignore_status);

{ Check to see if we are disconnected.

    IF jmv$ts_job_disconnected THEN
      jmp$timeout_timesharing_job (status);

    ELSE

{ Check to see if the task can do I/O on the connection.

      IF NOT pmp$ts_task_io_enabled () THEN
        pmp$establish_condition_handler (jmv$ts_interactive_condition, ^handle_condition,
              ^established_handler, status);
        IF NOT status.normal THEN
          log_unexpected_status (status);
        IFEND;

{ Wait for something to happen.

        WHILE NOT pmp$ts_task_io_enabled () DO
          pmp$long_term_wait (tmc$infinite_wait, 100000000);
        WHILEND;
        osp$set_status_condition (ife$pause_break_received, status);
        RETURN;
      IFEND;
    IFEND;
  PROCEND jmp$handle_ts_io_req_failure;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$handle_ts_system_disconnect', EJECT ??

  PROCEDURE [XDCL] jmp$handle_ts_system_disconnect
    (VAR status: ost$status);

    VAR
      timesharing_signal: jmt$timesharing_signal;

    status.normal := TRUE;

    IF jmv$timesharing_job THEN
      nlp$register_nominal_connection (osc$timesharing_terminal_file, status);
      IF NOT status.normal THEN
        log_unexpected_message ('Could not register the nominal connection in a recovered job.');
        log_unexpected_status (status);
        status.normal := TRUE;
      IFEND;

      timesharing_signal.signal_id := jmc$timesharing_signal_id;
      timesharing_signal.signal_contents.signal_kind := jmc$timesharing_disconnect;
      timesharing_signal.signal_contents.disconnect.disconnect_reason := jmc$ts_system_disconnect;

      pmp$send_signal (jmv$jcb.job_monitor_id, timesharing_signal.signal, status);
    IFEND;

    IF NOT status.normal THEN
      log_unexpected_status (status);
    IFEND;
  PROCEND jmp$handle_ts_system_disconnect;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$initialize_timesharing', EJECT ??

  PROCEDURE [XDCL] jmp$initialize_timesharing
    (VAR status: ost$status);

    CONST
      acquire_timeout = 60,
      max_connections = 1;

    VAR
      connection_attributes: ^nat$create_attributes,
      connection_exists: boolean,
      get_terminal_name: array [1 .. 1] of nat$accounting_data_field,
      ignore_status: ost$status,
      job_input_device_p: ^string ( * ),
      job_parameters: jmt$system_job_parameters,
      local_status: ost$status,
      mainframe_id: pmt$mainframe_id,
      paired_connection_data: jmt$paired_connection_data,
      submit_variation: jmt$submit_job_variations,
      wait_list_p: ^ost$i_wait_list,
      wait_complete: boolean,
      wait_activity: integer;


    status.normal := TRUE;
    jmv$timesharing_job := TRUE;

    job_parameters := jmv$kjlx_p^ [jmv$jcb.job_id].system_label_p^.job_attributes.system_job_parameters;

{ If there are no job parameters then the job is an initial submit on the local mainframe,
{ otherwise the type of submit is encoded in the job parameters

    PUSH connection_attributes: [1 .. 2];
    connection_attributes^ [1].kind := nac$data_transfer_timeout;
    connection_attributes^ [1].data_transfer_timeout := nac$max_wait_time;
    connection_attributes^ [2].kind := nac$receive_wait_swapout;
    connection_attributes^ [2].receive_wait_swapout := TRUE;

    IF job_parameters.system_job_parameter_count = 0 THEN
      nap$attach_server_application (osc$timesharing, max_connections, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      nap$acquire_connection (osc$timesharing, osc$timesharing_terminal_file, connection_attributes,
            acquire_timeout, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      nap$detach_server_application (osc$timesharing, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    ELSE
      i#move (^job_parameters.system_job_parameter, ^submit_variation, #SIZE (submit_variation));

      CASE submit_variation.kind OF
      = jmc$submit_detached_job =
        login_as_disconnected (status);
        RETURN;

      = jmc$connection_switch =

{ Wait for a switch offer to be made

        PUSH wait_list_p: [1 .. 2];
        wait_list_p^ [1].activity := osc$i_await_time;
        wait_list_p^ [1].milliseconds := connection_switch_timeout;
        wait_list_p^ [2].activity := nac$i_await_switch_offer;
        wait_list_p^ [2].source := submit_variation.job_offering_connection;
        osp$i_await_activity (wait_list_p^, wait_activity, wait_complete, status);

{ Did something go wrong or did we timeout? - if so - consider it an error

        IF (NOT status.normal) OR (wait_activity = 1) THEN
          log_unexpected_message ('A connection switch was never offered.');
          IF status.normal THEN
            osp$set_status_condition (ife$disconnected_job_timeout, status);
          IFEND;
          RETURN;
        IFEND;

        IF syv$clone_enabled AND syv$nosve_job_template THEN
          connection_exists := TRUE;
        ELSE
          connection_exists := FALSE;
        IFEND;

        nlp$accept_switch_offer (osc$timesharing_terminal_file, submit_variation.job_offering_connection,
              connection_attributes, connection_exists, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

      = jmc$remote_connection_switch =

        nap$attach_server_application (osc$timesharing, max_connections, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        nap$acquire_connection (osc$timesharing, osc$timesharing_terminal_file, connection_attributes,
              acquire_timeout, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        nap$detach_server_application (osc$timesharing, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        paired_connection_data.connection_request := jmc$pcr_leveled_job_results;
        paired_connection_data.leveled_job_results.successful := TRUE;

        iip$vtp_del_paired_con_first (#SEQ (paired_connection_data), local_status);
        IF NOT local_status.normal THEN
          log_unexpected_message ('initialize_timesharing - iip$vtp_del_paired_con_first failed with...');
          log_unexpected_status (local_status);
        IFEND;

      ELSE

{Unknown type of submit request

        osp$system_error ('Unknown submit request', NIL);
      CASEND;
    IFEND;

    nlp$register_nominal_connection (osc$timesharing_terminal_file, status);

    PUSH job_input_device_p: [jmv$kjlx_p^ [jmv$jcb.job_id].system_label_p^.job_attributes.job_input_device.
          size];
    job_input_device_p^ := jmv$kjlx_p^ [jmv$jcb.job_id].system_label_p^.job_attributes.job_input_device.text;
    get_terminal_name [1].kind := nac$ca_device_name;
    nap$parse_accounting_data (job_input_device_p, NIL, ^get_terminal_name, local_status);
    IF local_status.normal AND (get_terminal_name [1].kind = nac$ca_device_name) THEN
      qfp$set_terminal_name (get_terminal_name [1].device_name);
    ELSE
      qfp$set_terminal_name (osc$null_name);
    IFEND;
  PROCEND jmp$initialize_timesharing;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$set_interactive_cond_state', EJECT ??
*copy jmh$set_interactive_cond_state

  PROCEDURE [XDCL, #GATE] jmp$set_interactive_cond_state
    (    interactive_conditions_enabled: boolean);

    IF jmv$initialized_as_disconnected THEN
      jmv$interactive_conds_disabled := NOT interactive_conditions_enabled;
    IFEND;
  PROCEND jmp$set_interactive_cond_state;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$signal_pair_connect_target', EJECT ??
*copy jmh$signal_pair_connect_target

  PROCEDURE [XDCL] jmp$signal_pair_connect_target
    (    system_job_name: jmt$system_supplied_name;
     VAR status: ost$status);

    VAR
      job_internal_info: jmt$job_internal_information,
      reconnect_signal: jmt$timesharing_signal;

    status.normal := TRUE;

    jmp$get_job_internal_info (system_job_name, job_internal_info, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF NOT job_internal_info.timesharing_job THEN
      osp$set_status_abnormal ('JM', jme$incompatible_network_origin, system_job_name, status);
      RETURN;
    IFEND;

    reconnect_signal.signal_id := jmc$timesharing_signal_id;
    reconnect_signal.signal_contents.signal_kind := jmc$timesharing_reconnect;
    reconnect_signal.signal_contents.reconnect.system_supplied_job_name := jmv$jcb.system_name;
    reconnect_signal.signal_contents.reconnect.paired_connection_reconnect := TRUE;
    pmp$send_signal (job_internal_info.jmtr_global_taskid, reconnect_signal.signal, status);
  PROCEND jmp$signal_pair_connect_target;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$timeout_timesharing_job', EJECT ??

  PROCEDURE [XDCL] jmp$timeout_timesharing_job
    (VAR status: ost$status);

    VAR
      local_status: ost$status,
      signal: jmt$timesharing_signal;

?? NEWTITLE := 'handle_condition', EJECT ??

    PROCEDURE handle_condition
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           stack_frame_save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      VAR
        local_status: ost$status;

      IF condition.selector = pmc$block_exit_processing THEN

        jmv$ts_disconnect_time_left := 0;
      ELSE

        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);

        IF condition.selector = ifc$interactive_condition THEN
          CASE condition.interactive_condition OF
          = ifc$pause_break =
            osp$set_status_condition (ife$pause_break_received, status);

          = ifc$terminate_break =
            osp$set_status_condition (ife$terminate_break_received, status);

          = ifc$terminal_connection_broken =
            osp$set_status_condition (ife$connection_break_disconnect, status);

          = ifc$job_reconnect =
            osp$set_status_condition (ife$terminal_reconnected_to_job, status);

          ELSE
            osp$set_status_abnormal (ifc$interactive_facility_id, 0,
                  'unknown interactive condition encountered.', status);
          CASEND;

          EXIT jmp$timeout_timesharing_job;
        IFEND;
      IFEND;
    PROCEND handle_condition;
?? OLDTITLE ??
?? NEWTITLE := 'update_display_message', EJECT ??

{ PURPOSE:
{   The purpose of this request is to update the display message for display job
{ status to indicate when a job will timeout.

    PROCEDURE update_display_message
      (    timeout_time_left: integer);

      VAR
        current_date_time: ost$date_time,
        date: ost$date,
        local_status: ost$status,
        message_status: ost$status,
        time: ost$time,
        time_left: pmt$time_increment,
        timeout_time: ost$date_time;

      time_left.year := 0;
      time_left.month := 0;
      time_left.day := 0;
      time_left.hour := 0;
      time_left.minute := 0;
      time_left.second := timeout_time_left;
      time_left.millisecond := 0;

      pmp$get_compact_date_time (current_date_time, { ignore } local_status);
      pmp$compute_date_time (current_date_time, time_left, timeout_time, local_status);
      IF local_status.normal THEN
        pmp$format_compact_date (timeout_time, osc$iso_date, date, { ignore } local_status);
        pmp$format_compact_time (timeout_time, osc$hms_time, time, { ignore } local_status);
        osp$set_status_abnormal (jmc$job_management_id, jme$terminal_timeout_message, date.iso,
              message_status);
        osp$append_status_parameter (osc$status_parameter_delimiter, time.hms, message_status);
        jmp$update_display_message (message_status);
      IFEND;
    PROCEND update_display_message;
?? OLDTITLE ??
?? EJECT ??

    osp$establish_condition_handler (^handle_condition, {block_exit} TRUE);

    log_message ('Disconnect timeout begins.');

{ NOTE: all values used are in seconds.

    IF jmp$is_xterm_job () THEN

{ Xterm does not currently support attach job, so disconnect immediately.

      jmv$ts_disconnect_time_left := 0;
    ELSEIF jmv$ts_disconnect_time_left = 0 THEN
      jmv$ts_disconnect_time := #FREE_RUNNING_CLOCK (0) DIV 1000000;

{ Assign detach job wait time in seconds

      jmv$ts_disconnect_time_left := jmv$jcb.detached_job_wait_time;
    IFEND;

  /await_timeout/
    BEGIN
      WHILE jmv$ts_disconnect_time_left > 0 DO
        IF jmv$jcb.detached_job_wait_time = jmc$unlimited_det_job_wait_time THEN
          osp$set_status_condition (jme$unlimited_timeout_message, local_status);
          jmp$update_display_message (local_status);
        ELSE
          update_display_message (jmv$ts_disconnect_time_left);
        IFEND;
        pmp$long_term_wait (jmv$ts_disconnect_time_left * 1000, jmv$ts_disconnect_time_left * 1000);

{ Have we been reconnected ??

        IF NOT jmv$ts_job_disconnected THEN
          jmv$ts_disconnect_time_left := 0;
          EXIT /await_timeout/;
        IFEND;

        IF jmv$jcb.detached_job_wait_time <> jmc$unlimited_det_job_wait_time THEN
          jmv$ts_disconnect_time_left := jmv$jcb.detached_job_wait_time -
                ((#FREE_RUNNING_CLOCK (0) DIV 1000000) - jmv$ts_disconnect_time);

{ If the disconnect time left exceeds the detach job wait time, the free running
{ clock for the disconnect time must be in the future.  This could possible happen
{ during a recovery deadstart (although it isn't supposed to).
{ In any case, if this happens, restart the timeout from the beginning using
{ the current free-running clock as the detached time.

          IF jmv$ts_disconnect_time_left > jmv$jcb.detached_job_wait_time THEN
            jmv$ts_disconnect_time := #FREE_RUNNING_CLOCK (0) DIV 1000000;
            jmv$ts_disconnect_time_left := jmv$jcb.detached_job_wait_time;
          IFEND;
        IFEND;
      WHILEND;

{ The job has timed out - signal its death.

      IF NOT jmv$job_timed_out THEN
        signal.signal_id := jmc$timesharing_signal_id;
        signal.signal_contents.signal_kind := jmc$timesharing_timeout;
        pmp$send_signal (jmv$jcb.job_monitor_id, signal.signal, status);
        jmv$job_timed_out := TRUE;
      IFEND;

{ Return with abnormal status to the user

      osp$set_status_condition (jme$job_is_in_termination, status);
      osp$disestablish_cond_handler;
      RETURN;
    END /await_timeout/;

{ Can the task do IO?

    IF NOT pmp$ts_task_io_enabled () THEN
      WHILE NOT pmp$ts_task_io_enabled () DO
        pmp$long_term_wait (tmc$infinite_wait, 100000000);
      WHILEND;
      osp$set_status_condition (ife$pause_break_received, status);
      osp$disestablish_cond_handler;
      RETURN;
    IFEND;

    osp$disestablish_cond_handler;
    status.normal := TRUE;
  PROCEND jmp$timeout_timesharing_job;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$timesharing_signal_handler', EJECT ??

  PROCEDURE [XDCL] jmp$timesharing_signal_handler
    (    originator: ost$global_task_id;
         signal: pmt$signal);

    VAR
      local_status: ost$status,
      executing_in_job_synch_task: boolean,
      signal_processed: boolean,
      executing_gtid: ost$global_task_id,
      statistic_data: jmt$comm_acct_statistic_data,
      submit_variation: jmt$submit_job_variations,
      timesharing_signal: jmt$timesharing_signal;

?? NEWTITLE := 'check_for_special_signals', EJECT ??

    PROCEDURE check_for_special_signals
      (    timesharing_signal: jmt$timesharing_signal;
       VAR processed_signal: boolean;
       VAR status: ost$status);

      VAR
        display_option_selection: lgt$display_option_selection,
        job_name: clt$data_value,
        job_name_p: ^jmt$job_attribute_results,
        message: [STATIC, READ, oss$job_paged_literal] string (2) := $CHAR (0D(16)) CAT $CHAR (0A(16)),
        cl_processing_phase: clt$processing_phase;


      status.normal := TRUE;
      processed_signal := TRUE;

      CASE timesharing_signal.signal_contents.signal_kind OF
      = jmc$timesharing_interrupt =

{ A user interrupt was received.  Process the interrupt.

        clp$get_processing_phase (cl_processing_phase, status);
        IF status.normal AND (clc$user_prolog_phase <= cl_processing_phase) AND
              (cl_processing_phase <= clc$user_epilog_phase) AND (NOT jmv$interactive_conds_disabled) THEN

          IF NOT jmv$terminal_io_disabled THEN
            CASE timesharing_signal.signal_contents.interrupt (1) OF
            = 'A', 'a' =
              pmp$display_active_tasks (':$LOCAL.OUTPUT.1', status);
              put_and_flush_output (message, status);

            = 'D', 'd' =
              jmp$detach_timesharing_job (status);

            = 'J', 'j' =
              job_name.kind := clc$keyword;
              job_name.keyword_value := 'ALL';
              jmp$display_job_status (':$LOCAL.OUTPUT.1', $jmt$attribute_keys_set
                    [jmc$cpu_time_used, jmc$display_message, jmc$job_state, jmc$page_faults,
                    jmc$system_job_name], job_name, status);
              put_and_flush_output (message, status);

            = 'L', 'l' =
              display_option_selection.display_options := lgc$count;
              display_option_selection.count := 10;
              lgp$display_log (clc$display_job_log, display_option_selection, ':$LOCAL.OUTPUT.1', status);
              put_and_flush_output (message, status);

            = 'X', 'x' =
              ;
            ELSE
              job_name.kind := clc$name;
              PUSH job_name_p: [1 .. 1];
              job_name_p^ [1].key := jmc$system_job_name;
              jmp$get_job_attributes (job_name_p, status);
              job_name.name_value := job_name_p^ [1].system_job_name;
              jmp$display_job_status (':$LOCAL.OUTPUT.1', $jmt$attribute_keys_set
                    [jmc$cpu_time_used, jmc$display_message, jmc$page_faults], job_name, status);
              put_and_flush_output (message, status);
            CASEND;
          IFEND;

          CASE timesharing_signal.signal_contents.interrupt (1) OF
          = 'X', 'x' =
            osp$set_status_condition (jme$user_requested_exit, status);
            pmp$exit (status);

          ELSE
          CASEND;

        ELSE {before user prolog or after user epilog}
          log_message ('User interrupt ignored');
          status.normal := TRUE;
        IFEND;

      = jmc$timesharing_restart_tasks =

{ Restart the appropriate task(s).

        IF timesharing_signal.signal_contents.restart_tasks = jmc$ts_restart_child_tasks THEN
          pmp$signal_all_child_tasks (timesharing_signal.signal, status);
        IFEND;

      = jmc$timesharing_timeout =

        log_message ('Disconnect timeout completed.');

{ The job has been disconnected for the detached job wait time.  Let's end it.

        osp$set_status_condition (ife$disconnected_job_timeout, status);
        pmp$exit (status);

      ELSE
        processed_signal := FALSE;
      CASEND;
    PROCEND check_for_special_signals;
?? OLDTITLE ??
?? NEWTITLE := 'raise_condition', EJECT ??

    PROCEDURE raise_condition
      (    timesharing_signal: jmt$timesharing_signal);

?? NEWTITLE := 'handle_disconnect', EJECT ??

      PROCEDURE handle_disconnect
        (    timesharing_signal: jmt$timesharing_signal;
         VAR cause_condition: boolean);

        CONST
          paired_connect_timeout_interval = 120000; { in milliseconds

        VAR
          current_clock: ost$free_running_clock,
          current_mainframe_id: pmt$binary_mainframe_id,
          file_id: amt$file_identifier,
          destination_title: ost$name,
          job_termination_options: ^jmt$job_termination_options,
          paired_connection_data: jmt$paired_connection_data,
          paired_connection_data_p: ^jmt$paired_connection_data,
          termination_data_p: ^SEQ ( * ),
          termination_attributes_p: ^nat$get_attributes,
          submitted_job_name: jmt$name,
          wait_list_p: ^ost$i_wait_list,
          wait_complete: boolean,
          wait_activity: integer,
          wait_file: amt$local_file_name,
          job_attribute_p: ^jmt$job_attribute_results,
          job_submission_options: ^jmt$job_submission_options,
          reconnect_signal: jmt$timesharing_signal,
          terminate_signal: jmt$timesharing_signal,
          unsimulate_broken_status: ost$status,
          time_left: integer,
          local_status: ost$status,
          ignore_status: ost$status;

?? NEWTITLE := 'send_line_disconnect', EJECT ??

        PROCEDURE send_line_disconnect;

          VAR
            local_status: ost$status,
            disconnect_signal: jmt$timesharing_signal;

          log_message ('The job was disconnected while a non-nominal operation was pending.');

          disconnect_signal.signal_id := jmc$timesharing_signal_id;
          disconnect_signal.signal_contents.signal_kind := jmc$timesharing_disconnect;
          disconnect_signal.signal_contents.disconnect.disconnect_reason := jmc$ts_line_disconnect;
          pmp$send_signal (jmv$jcb.job_monitor_id, disconnect_signal.signal, local_status);
        PROCEND send_line_disconnect;

?? OLDTITLE, EJECT ??

        unsimulate_broken_status.normal := TRUE;
        cause_condition := TRUE;

        CASE timesharing_signal.signal_contents.disconnect.disconnect_reason OF

        = jmc$ts_line_disconnect =
          jmp$set_job_mode (jmc$interactive_line_disconnect, ignore_status);

        = jmc$ts_attach_job =

          pmp$get_pseudo_mainframe_id (current_mainframe_id);
          IF current_mainframe_id = timesharing_signal.signal_contents.disconnect.target_job_mainframe_id THEN

{ Offer the target job the connection

            nlp$offer_connection_switch (osc$timesharing_terminal_file,
                  timesharing_signal.signal_contents.disconnect.target_job_system_supplied_name, TRUE,
                  local_status);
            IF NOT local_status.normal THEN
              log_unexpected_status (local_status);
              nlp$unsimulate_connection_broke (osc$timesharing_terminal_file, unsimulate_broken_status);
              IF pmp$zero_ts_conditions_in_task () THEN
                pmp$enable_ts_io_in_tasks;
              IFEND;
              nlp$register_nominal_connection (osc$timesharing_terminal_file, ignore_status);
              jmv$ts_job_disconnected := FALSE;
              IF NOT unsimulate_broken_status.normal THEN
                send_line_disconnect;
              ELSE
                output_message (' The attempt to offer the switch to the target job failed.');
              IFEND;
              cause_condition := FALSE;
              RETURN;
            IFEND;

{ Signal the target with a reconnect request using the SSN and target GTID

            reconnect_signal.signal_id := jmc$timesharing_signal_id;
            reconnect_signal.signal_contents.signal_kind := jmc$timesharing_reconnect;
            reconnect_signal.signal_contents.reconnect.system_supplied_job_name := jmv$jcb.system_name;
            reconnect_signal.signal_contents.reconnect.paired_connection_reconnect := FALSE;
            pmp$send_signal (timesharing_signal.signal_contents.disconnect.target_job_global_task_id,
                  reconnect_signal.signal, local_status);
            IF NOT local_status.normal THEN
              log_unexpected_status (local_status);
              nap$cancel_switch_offer (osc$timesharing_terminal_file, ignore_status);
              nlp$unsimulate_connection_broke (osc$timesharing_terminal_file, unsimulate_broken_status);
              IF pmp$zero_ts_conditions_in_task () THEN
                pmp$enable_ts_io_in_tasks;
              IFEND;
              nlp$register_nominal_connection (osc$timesharing_terminal_file, ignore_status);
              jmv$ts_job_disconnected := FALSE;
              IF NOT unsimulate_broken_status.normal THEN
                send_line_disconnect;
              ELSE
                output_message (' The attempt to signal the target job failed.');
              IFEND;
              cause_condition := FALSE;
              RETURN;
            IFEND;

{ Wait for the signaled job to pick up to connection

            PUSH wait_list_p: [1 .. 2];
            wait_list_p^ [1].activity := osc$i_await_time;
            wait_list_p^ [1].milliseconds := connection_switch_timeout;
            wait_list_p^ [2].activity := nac$i_await_switch_accept;
            wait_file := osc$timesharing_terminal_file;
            wait_list_p^ [2].file := ^wait_file;
            osp$i_await_activity (wait_list_p^, wait_activity, wait_complete, local_status);

{ Did something go wrong or did we timeout? - if so - consider it an error an back out.

            IF (NOT local_status.normal) OR (wait_activity = 1) THEN
              IF local_status.normal THEN
                log_message ('The switch offer was not accepted by the target job.');
              ELSE
                log_unexpected_status (local_status);
              IFEND;
              nap$cancel_switch_offer (osc$timesharing_terminal_file, ignore_status);
              nlp$unsimulate_connection_broke (osc$timesharing_terminal_file, unsimulate_broken_status);
              IF pmp$zero_ts_conditions_in_task () THEN
                pmp$enable_ts_io_in_tasks;
              IFEND;
              nlp$register_nominal_connection (osc$timesharing_terminal_file, ignore_status);
              jmv$ts_job_disconnected := FALSE;
              IF NOT unsimulate_broken_status.normal THEN
                send_line_disconnect;
              ELSE
                output_message (' The switch offer was not accepted by the target job.');
              IFEND;
              cause_condition := FALSE;
              RETURN;
            IFEND;

          ELSE { The job is on a different mainframe
            paired_connection_data.connection_request := jmc$pcr_attach_job_request;
            paired_connection_data.attach_job_request.system_job_name :=
                  timesharing_signal.signal_contents.disconnect.target_job_system_supplied_name;
            jmp$get_encrypted_password (paired_connection_data.attach_job_request.encrypted_password,
                  ignore_status);
            jmp$generate_timesharing_title (timesharing_signal.signal_contents.disconnect.
                  target_job_mainframe_id, destination_title);

{ IO in all tasks has ended.  Enable IO (that is, back out of the simulation of
{ the disconnect).  This will allow this task to do IO on the connection, which is
{ required in order to create a paired connection.
{ It is possible that the job will disconnect while in wait.  In fact, a clear
{ will be sent from the other host which will cause a disconnect to occur.
{ If that is the case, This request was sucessful.

            nlp$unsimulate_connection_broke (osc$timesharing_terminal_file, unsimulate_broken_status);
            jmv$ts_job_disconnected := FALSE;

            clp$get_system_file_id (clc$job_output, file_id, ignore_status);
            iip$vtp_create_paired_connect (file_id, destination_title, #SEQ (paired_connection_data),
                  paired_connect_timeout_interval, local_status);
            IF NOT local_status.normal THEN
              log_unexpected_message ('Create paired connection failed with...');
              log_unexpected_status (local_status);
              paired_connection_data.connection_request := jmc$pcr_attach_job_results;
              paired_connection_data.attach_job_results.successful := FALSE;
              iip$vtp_delete_paired_connect (file_id, #SEQ (paired_connection_data), local_status);
              IF NOT local_status.normal THEN
                log_unexpected_message ('Delete paired connection failed with...');
                log_unexpected_status (local_status);
              IFEND;
              IF NOT jmv$ts_job_disconnected THEN
                IF pmp$zero_ts_conditions_in_task () THEN
                  pmp$enable_ts_io_in_tasks;
                IFEND;
                nlp$register_nominal_connection (osc$timesharing_terminal_file, ignore_status);
                output_message (' The attempt to reconnect to the target job failed.');
              IFEND;
              cause_condition := FALSE;
              RETURN;
            IFEND;

            PUSH termination_attributes_p: [1 .. 1];
            termination_attributes_p^ [1].kind := nac$connection_state;
            termination_attributes_p^ [1].connection_state := nac$established;
            current_clock := #FREE_RUNNING_CLOCK (0);
            time_left := paired_connect_timeout_interval;
            WHILE (NOT jmv$ts_job_disconnected) AND (time_left > 0) AND
                  (termination_attributes_p^ [1].connection_state <> nac$terminated) DO
              pmp$long_term_wait (time_left DIV 12, time_left DIV 12);
              nap$get_attributes (osc$timesharing_terminal_file, termination_attributes_p^, local_status);
              time_left := paired_connect_timeout_interval - ((#FREE_RUNNING_CLOCK (0) - current_clock) DIV
                    1000);
            WHILEND;

            IF jmv$ts_job_disconnected OR (termination_attributes_p^ [1].connection_state =
                  nac$terminated) THEN

{ Need to look at the peer termination data to verify that the job was disconnected due
{ to a successful attach job request - The peer termination data should contain the
{ fact that the attach job request was successful.

              PUSH termination_data_p: [[REP 256 OF cell]];
              PUSH termination_attributes_p: [1 .. 1];
              termination_attributes_p^ [1].kind := nac$peer_termination_data;
              termination_attributes_p^ [1].peer_termination_data := termination_data_p;
              nap$get_attributes (osc$timesharing_terminal_file, termination_attributes_p^, local_status);
              IF NOT local_status.normal THEN
                log_unexpected_message ('Unable to get peer termination data for a paired connection.');
                log_unexpected_status (local_status);
                cause_condition := FALSE;
                RETURN;
              ELSE
                RESET termination_data_p;
                NEXT paired_connection_data_p IN termination_data_p;
                IF (paired_connection_data_p = NIL) OR (termination_attributes_p^ [1].
                      peer_termination_data_length < #SIZE (paired_connection_data_p^)) OR
                      (paired_connection_data_p^.connection_request <> jmc$pcr_attach_job_results) OR
                      (NOT paired_connection_data_p^.attach_job_results.successful) THEN

                  log_message (
                        'Job disconnected while waiting for partner mainframe to delete the connection.');
                  cause_condition := FALSE;
                  RETURN;
                IFEND;
              IFEND;
            ELSE

{ Backout - The job should have been disconnected.  The target job must not have picked up the connection.
{   Delete the paired connection and return.

              log_unexpected_message ('The target job failed to delete the paired connection.');
              paired_connection_data.connection_request := jmc$pcr_attach_job_results;
              paired_connection_data.attach_job_results.successful := FALSE;
              iip$vtp_delete_paired_connect (file_id, #SEQ (paired_connection_data), local_status);
              IF NOT local_status.normal THEN
                log_unexpected_message ('Delete paired connection failed with...');
                log_unexpected_status (local_status);
              IFEND;
              IF NOT jmv$ts_job_disconnected THEN
                IF pmp$zero_ts_conditions_in_task () THEN
                  pmp$enable_ts_io_in_tasks;
                IFEND;
                nlp$register_nominal_connection (osc$timesharing_terminal_file, ignore_status);
                output_message (' The attempt to reconnect to the target job failed.');
              IFEND;
              cause_condition := FALSE;
              RETURN;
            IFEND;

          IFEND;

{ Signal the job_monitor task to go away (timeout)

          terminate_signal.signal_id := jmc$timesharing_signal_id;
          terminate_signal.signal_contents.signal_kind := jmc$timesharing_timeout;
          pmp$send_signal (jmv$jcb.job_monitor_id, terminate_signal.signal, ignore_status);

{ Set the job mode to tell the world that the job is disconnected.

          jmp$set_job_mode (jmc$interactive_cmnd_disconnect, ignore_status);




        = jmc$ts_detach_job =

{ Get the required information about the user

          PUSH job_attribute_p: [1 .. 5];
          job_attribute_p^ [1].key := jmc$login_family;
          job_attribute_p^ [2].key := jmc$login_user;
          job_attribute_p^ [3].key := jmc$login_account;
          job_attribute_p^ [4].key := jmc$login_project;
          job_attribute_p^ [5].key := jmc$job_class;
          jmp$get_job_attributes (job_attribute_p, ignore_status);

{ Submit a job with the SSN value for system job parameters

          PUSH job_submission_options: [1 .. 10];
          job_submission_options^ [1].key := jmc$origin_application_name;
          job_submission_options^ [1].origin_application_name := osc$timesharing;
          job_submission_options^ [2].key := jmc$login_command_supplied;
          job_submission_options^ [2].login_command_supplied := FALSE;
          job_submission_options^ [3].key := jmc$login_family;
          job_submission_options^ [3].login_family := job_attribute_p^ [1].login_family;
          job_submission_options^ [4].key := jmc$login_user;
          job_submission_options^ [4].login_user := job_attribute_p^ [2].login_user;
          job_submission_options^ [5].key := jmc$immediate_init_candidate;
          job_submission_options^ [5].immediate_init_candidate := TRUE;
          job_submission_options^ [6].key := jmc$job_class;
          job_submission_options^ [6].job_class := job_attribute_p^ [5].job_class;
          job_submission_options^ [7].key := jmc$system_job_parameters;
          PUSH job_submission_options^ [7].system_job_parameters;
          job_submission_options^ [8].key := jmc$login_account;
          job_submission_options^ [8].login_account := job_attribute_p^ [3].login_account;
          job_submission_options^ [9].key := jmc$login_project;
          job_submission_options^ [9].login_project := job_attribute_p^ [4].login_project;
          job_submission_options^ [10].key := jmc$job_destination_usage;
          job_submission_options^ [10].job_destination_usage := jmc$ve_local_usage;
          submit_variation.kind := jmc$connection_switch;
          submit_variation.job_offering_connection := jmv$jcb.system_name;
          job_submission_options^ [7].system_job_parameters^.system_job_parameter_count :=
                #SIZE (submit_variation);
          i#move (^submit_variation, ^job_submission_options^ [7].system_job_parameters^.
                system_job_parameter, #SIZE (submit_variation));
          submitted_job_name.kind := jmc$system_supplied_name;

          jmp$submit_job (clc$null_file, job_submission_options, submitted_job_name.system_supplied_name,
                local_status);
          IF NOT local_status.normal THEN
            log_status (local_status);
            nlp$unsimulate_connection_broke (osc$timesharing_terminal_file, unsimulate_broken_status);
            IF pmp$zero_ts_conditions_in_task () THEN
              pmp$enable_ts_io_in_tasks;
            IFEND;
            nlp$register_nominal_connection (osc$timesharing_terminal_file, ignore_status);
            jmv$ts_job_disconnected := FALSE;
            IF NOT unsimulate_broken_status.normal THEN
              send_line_disconnect;
            ELSE
              output_message (' The attempt to submit a new job failed - see the job log for details.');
            IFEND;
            cause_condition := FALSE;
            RETURN;
          IFEND;

{ Offer the submitted job the connection

          nlp$offer_connection_switch (osc$timesharing_terminal_file, submitted_job_name.system_supplied_name,
                TRUE, local_status);
          IF NOT local_status.normal THEN
            log_unexpected_status (local_status);
            PUSH job_termination_options: [1 .. 1];
            job_termination_options^ [1].key := jmc$output_disposition;
            job_termination_options^ [1].output_disposition.key := jmc$discard_standard_output;
            jmp$terminate_job (submitted_job_name, job_termination_options, ignore_status);
            nlp$unsimulate_connection_broke (osc$timesharing_terminal_file, unsimulate_broken_status);
            IF pmp$zero_ts_conditions_in_task () THEN
              pmp$enable_ts_io_in_tasks;
            IFEND;
            nlp$register_nominal_connection (osc$timesharing_terminal_file, ignore_status);
            jmv$ts_job_disconnected := FALSE;
            IF NOT unsimulate_broken_status.normal THEN
              send_line_disconnect;
            ELSE
              output_message (' The attempt to offer the connection to the new job failed.');
            IFEND;
            cause_condition := FALSE;
            RETURN;
          IFEND;

{ Wait for the job submitted to pick up the connection.

          PUSH wait_list_p: [1 .. 2];
          wait_list_p^ [1].activity := osc$i_await_time;
          wait_list_p^ [1].milliseconds := connection_switch_timeout;
          wait_list_p^ [2].activity := nac$i_await_switch_accept;
          wait_file := osc$timesharing_terminal_file;
          wait_list_p^ [2].file := ^wait_file;
          osp$i_await_activity (wait_list_p^, wait_activity, wait_complete, local_status);

{ Did something go wrong or did we timeout? - if so - consider it an error and back out.

          IF (NOT local_status.normal) OR (wait_activity = 1) THEN
            IF local_status.normal THEN
              log_message ('The switch offer was not accepted by the new job.');
            ELSE
              log_unexpected_status (local_status);
            IFEND;
            nap$cancel_switch_offer (osc$timesharing_terminal_file, ignore_status);
            PUSH job_termination_options: [1 .. 1];
            job_termination_options^ [1].key := jmc$output_disposition;
            job_termination_options^ [1].output_disposition.key := jmc$discard_standard_output;
            jmp$terminate_job (submitted_job_name, job_termination_options, ignore_status);
            nlp$unsimulate_connection_broke (osc$timesharing_terminal_file, unsimulate_broken_status);
            IF pmp$zero_ts_conditions_in_task () THEN
              pmp$enable_ts_io_in_tasks;
            IFEND;
            nlp$register_nominal_connection (osc$timesharing_terminal_file, ignore_status);
            jmv$ts_job_disconnected := FALSE;
            IF NOT unsimulate_broken_status.normal THEN
              send_line_disconnect;
            ELSE
              output_message (' The switch offer was not accepted by the new job.');
            IFEND;
            cause_condition := FALSE;
            RETURN;
          IFEND;

{ Set the job mode to let the world know that the job is disconnected.

          jmp$set_job_mode (jmc$interactive_cmnd_disconnect, ignore_status);

        = jmc$ts_system_disconnect =
          jmp$set_job_mode (jmc$interactive_sys_disconnect, ignore_status);

        ELSE
          log_unexpected_message ('An unknown disconnect message was received.');
          output_message ('A problem occured within disconnect processing - see the job log for details');
          cause_condition := FALSE;
          RETURN;
        CASEND;


{ Emit the statistic AV21 for all cases of disconnect_reason

        sfp$emit_statistic (avc$detach_job, '', NIL, ignore_status);


        log_message ('Interactive disconnect.');

      PROCEND handle_disconnect;
?? OLDTITLE ??
?? NEWTITLE := 'handle_reconnect', EJECT ??

      PROCEDURE handle_reconnect
        (    timesharing_signal: jmt$timesharing_signal;
         VAR cause_condition: boolean);

        VAR
          file_id: amt$file_identifier,
          get_attributes: array [1 .. 1] of nat$get_attribute,
          get_terminal_name: array [1 .. 1] of nat$accounting_data_field,
          ignore_status: ost$status,
          job_attribute_p: ^jmt$job_attribute_results,
          job_input_device: jmt$job_input_device,
          local_status: ost$status,
          operation_information_p: ^sft$audit_information,
          operation_status_p: ^ost$status,
          paired_connection_data: jmt$paired_connection_data,
          peer_accounting_info: ^string ( * );

{ Accept the switch offer using the SSN in the signal

        nlp$accept_switch_offer (osc$timesharing_terminal_file,
              timesharing_signal.signal_contents.reconnect.system_supplied_job_name, NIL, TRUE, local_status);
        IF NOT local_status.normal THEN
          log_unexpected_message ('Could not get the switched connection.');
          log_unexpected_status (local_status);
          IF pmp$zero_ts_conditions_in_task () THEN
            pmp$enable_ts_io_in_tasks;
            cause_condition := FALSE;
            RETURN;
          IFEND;
        IFEND;

{ At this point we are committed to attaching the job to the terminal.

        IF timesharing_signal.signal_contents.reconnect.paired_connection_reconnect THEN
          paired_connection_data.connection_request := jmc$pcr_attach_job_results;
          paired_connection_data.attach_job_results.successful := TRUE;

{ Allow the job to do IO on a connection.  This allows another task to open
{ the file to delete the paired connection.

          jmv$ts_job_disconnected := FALSE;
          pmp$enable_timesharing_io;
          clp$get_system_file_id (clc$job_output, file_id, ignore_status);
          iip$vtp_delete_paired_connect (file_id, #SEQ (paired_connection_data), local_status);
          jmv$ts_job_disconnected := TRUE;
          IF NOT local_status.normal THEN
            log_unexpected_message ('handle_reconnect - iip$vtp_delete_paired_connect failed with...');
            log_unexpected_status (local_status);
          IFEND;
        IFEND;

        nlp$register_nominal_connection (osc$timesharing_terminal_file, ignore_status);

{ Emit the statistic AV22 for the reconnected job

        sfp$emit_statistic (avc$attach_job, '', NIL, ignore_status);

{ Change the job mode to connected

        jmp$set_job_mode (jmc$interactive_connected, ignore_status);

{ Reset the Terminal_Name terminal attribute in the connection description and the
{ Job_Input_Device job attribute.

        get_attributes [1].kind := nac$peer_accounting_information;
        PUSH get_attributes [1].peer_accounting_information: [[REP 256 OF char]];
        nap$get_attributes (osc$timesharing_terminal_file, get_attributes, local_status);
        IF NOT local_status.normal THEN
          log_message ('Error getting Peer Accounting Information from NAP$GET_ATTRIBUTES.');
          log_status (local_status);
        IFEND;

        IF get_attributes [1].peer_accounting_info_length <> 0 THEN
          RESET get_attributes [1].peer_accounting_information;
          NEXT peer_accounting_info: [get_attributes [1].peer_accounting_info_length] IN
                get_attributes [1].peer_accounting_information;

          job_input_device.size := get_attributes [1].peer_accounting_info_length;
          job_input_device.text := peer_accounting_info^;
          jmp$set_job_input_device (job_input_device);

          get_terminal_name [1].kind := nac$ca_device_name;
          nap$parse_accounting_data (peer_accounting_info, NIL, ^get_terminal_name, local_status);
          IF local_status.normal AND (get_terminal_name [1].kind = nac$ca_device_name) THEN
            iip$set_terminal_name (get_terminal_name [1].device_name);
          ELSE
            IF NOT local_status.normal THEN
              log_message ('Error getting Device Name from NAP$PARSE_ACCOUNTING_DATA.');
            IFEND;
            iip$set_terminal_name (osc$null_name);
          IFEND;
        ELSE
          iip$set_terminal_name (osc$null_name);
        IFEND;

{ Emit the audit statistic if necessary.

        IF avp$security_option_active (avc$vso_security_audit) THEN
          PUSH job_attribute_p: [1 .. 4];
          job_attribute_p^ [1].key := jmc$login_family;
          job_attribute_p^ [2].key := jmc$login_user;
          job_attribute_p^ [3].key := jmc$login_account;
          job_attribute_p^ [4].key := jmc$login_project;
          jmp$get_job_attributes (job_attribute_p, ignore_status);

          PUSH operation_information_p;
          operation_information_p^.audited_operation := sfc$ao_job_user_identification;
          operation_information_p^.user_identification.family_name_p := ^job_attribute_p^ [1].login_family;
          operation_information_p^.user_identification.user_name_p := ^job_attribute_p^ [2].login_user;
          operation_information_p^.user_identification.account_name_p := ^job_attribute_p^ [3].login_account;
          operation_information_p^.user_identification.project_name_p := ^job_attribute_p^ [4].login_project;
          IF local_status.normal AND (get_terminal_name [1].kind = nac$ca_device_name) THEN
            operation_information_p^.user_identification.terminal_name_p := ^get_terminal_name [1].
                  device_name;
          ELSE
            operation_information_p^.user_identification.terminal_name_p := NIL;
          IFEND;
          PUSH operation_status_p;
          operation_status_p^.normal := TRUE;
          sfp$emit_audit_statistic (operation_information_p^, operation_status_p^);
        IFEND;

{ Unmark the job as being disconnected

        log_message ('Interactive reconnect.');
        jmv$ts_job_disconnected := FALSE;

{ Restore the active connection attributes of the reconnected job.

        iip$restore_term_conn_atributes (local_status);
        IF NOT local_status.normal THEN
          log_unexpected_message ('Error restoring the active connection attributes of the reconnected job.');
          log_unexpected_status (local_status);
        IFEND;

      PROCEND handle_reconnect;
?? OLDTITLE ??
?? NEWTITLE := 'confirm_synchronization', EJECT ??

      PROCEDURE confirm_synchronization
        (VAR status: ost$status);

        VAR
          ignore_status: ost$status,
          terminal_file_id: amt$file_identifier;

        fsp$open_file (osc$timesharing_terminal_file, amc$record, NIL, NIL, NIL, NIL, NIL, terminal_file_id,
              status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        nap$se_synchronize_confirm (terminal_file_id, status);
        IF NOT status.normal THEN
          fsp$close_file (terminal_file_id, ignore_status);
          RETURN;
        IFEND;

        fsp$close_file (terminal_file_id, status);
      PROCEND confirm_synchronization;

?? OLDTITLE, EJECT ??

      VAR
        condition_id: ift$interactive_condition,
        cause_condition: boolean,
        local_status: ost$status,
        ignore_status: ost$status;

      cause_condition := TRUE;

      CASE timesharing_signal.signal_contents.signal_kind OF

      = jmc$timesharing_disconnect =
        condition_id := ifc$terminal_connection_broken;

        handle_disconnect (timesharing_signal, cause_condition);
        IF (NOT cause_condition) THEN
          RETURN;
        IFEND;

{ Enable IO within this task - this request must take place only when if
{ a condition is going to be raised.

        pmp$begin_timesharing_condition;
        pmp$enable_timesharing_io;

{ We must back-out of the condition state for the task.  That is, pretend as though a handler was called and
{ ate the condition and then returned.  This is a kludge, but it is cleaner than confusing the normal path
{ of conditions through timesharing more than it is.
{ The above requests, pmp$begin_timesharing_condition and pmp$enable_timesharing_io have the effect as
{ follows:
{ o The task's condition count in the TCB is incremented by one.
{ o The task's enable/disable flag for terminal IO is enabled.
{ If a condition is not going to be raised, the task's condition count must, potentially be reduced...but we
{ can't unconditionally reset it to zero.  The number of conditions within a task, only goes to zero when the
{ number of handlers processing that condition goes from one to zero (see module design section).  This is
{ complicated by the presence of multiple synch requests from the user.  Therefore, treat it as though a
{ condition handler were called, jmp$begin_timesharing_handler and the condition handler ate the condition.
{ This returns control and jmp$end_timesharing_handler is called, which, if necessary, will put the TCB back
{ into the proper state.  This is analogous to what pmp$dispose_interactive_cond does.

        IF jmv$interactive_conds_disabled THEN
          jmp$begin_timesharing_handler (condition_id);
          jmp$end_timesharing_handler (condition_id);
          RETURN;
        IFEND;

      = jmc$timesharing_reconnect =
        condition_id := ifc$job_reconnect;

        handle_reconnect (timesharing_signal, cause_condition);
        IF (NOT cause_condition) THEN
          RETURN;
        IFEND;

{ Enable IO within this task - this request must take place only when if
{ a condition is going to be raised.

        pmp$begin_timesharing_condition;
        pmp$enable_timesharing_io;

{ We must back-out of the condition state for the task.  That is, pretend as though a handler was called and
{ ate the condition and then returned.  This is a kludge, but it is cleaner than confusing the normal path
{ of conditions through timesharing more than it is.
{ The above requests, pmp$begin_timesharing_condition and pmp$enable_timesharing_io have the effect as
{ follows:
{ o The task's condition count in the TCB is incremented by one.
{ o The task's enable/disable flag for terminal IO is enabled.
{ If a condition is not going to be raised, the task's condition count must, potentially be reduced...but we
{ can't unconditionally reset it to zero.  The number of conditions within a task, only goes to zero when the
{ number of handlers processing that condition goes from one to zero (see module design section).  This is
{ complicated by the presence of multiple synch requests from the user.  Therefore, treat it as though a
{ condition handler were called, jmp$begin_timesharing_handler and the condition handler ate the condition.
{ This returns control and jmp$end_timesharing_handler is called, which, if necessary, will put the TCB back
{ into the proper state.  This is analogous to what pmp$dispose_interactive_cond does.

        IF jmv$interactive_conds_disabled THEN
          jmp$begin_timesharing_handler (condition_id);
          jmp$end_timesharing_handler (condition_id);
          RETURN;
        IFEND;

      = jmc$timesharing_synchronize =

{ Enable IO within this task - this request must take place before synchronization takes place
{ otherwise the job can hang.  If this is not the job monitor task, and we synchronize first, and
{ then enable IO, the job monitor task could begin processing another synch request and disable IO
{ and this could radically confuse the enable/disable state of a task so far as terminal IO is
{ concerned.

        pmp$begin_timesharing_condition;
        pmp$enable_timesharing_io;

{ This request synchronizes the connection - this enables NAM/VE to send additional synchronize
{ requests - we will ignore such requests until we go into a long term wait or exit from ring three.
{ If this request should ever fail for some reason - the job will hang - as a result of this
{ occuring - an attempt will be made to bring the job down as if the user had entered logout.
{ If the request should fail due to a connection broken, an error will be returned - in this case,
{ the desired solution is to "ignore" the synchronize and not raise a condition.

        confirm_synchronization (local_status);
        IF NOT local_status.normal THEN
          IF (local_status.condition = nae$connection_terminated) OR
                (local_status.condition = nae$connection_not_established) THEN
            RETURN; { Don't raise the condition
          ELSE
            log_unexpected_status (local_status);
            log_unexpected_message ('An attempt to synchronize a NAM/VE connection has occured.');
            log_unexpected_message ('Attempting to logout the job gracefully.');
            jmp$logout (ignore_status);
          IFEND;
        IFEND;

        IF timesharing_signal.signal_contents.synchronize (1) = pause_break_char THEN
          condition_id := ifc$pause_break;
        ELSE
          condition_id := ifc$terminate_break;
        IFEND;

        log_message ('User break received.');

        IF jmv$terminal_io_disabled OR (NOT jmv$user_breaks_enabled) OR (jmv$interactive_conds_disabled) THEN

{ We must back-out of the condition state for the task.  That is, pretend as though a handler was called and
{ ate the condition and then returned.  This is a kludge, but it is cleaner than confusing the normal path
{ of conditions through timesharing more than it is.
{ The above requests, pmp$begin_timesharing_condition and pmp$enable_timesharing_io have the effect as
{ follows:
{ o The task's condition count in the TCB is incremented by one.
{ o The task's enable/disable flag for terminal IO is enabled.
{ If a condition is not going to be raised, the task's condition count must, potentially be reduced...but we
{ can't unconditionally reset it to zero.  The number of conditions within a task, only goes to zero when the
{ number of handlers processing that condition goes from one to zero (see module design section).  This is
{ complicated by the presence of multiple synch requests from the user.  Therefore, treat it as though a
{ condition handler were called, jmp$begin_timesharing_handler and the condition handler ate the condition.
{ This returns control and jmp$end_timesharing_handler is called, which, if necessary, will put the TCB back
{ into the proper state.  This is analogous to what pmp$dispose_interactive_cond does.

          jmp$begin_timesharing_handler (condition_id);
          jmp$end_timesharing_handler (condition_id);
          RETURN;
        IFEND

      ELSE
        log_unexpected_message ('An attempt was made to raise an unknown interactive condition.');
        output_message ('A unknown interactive condition has occured - examine the job log for details.');
        RETURN;
      CASEND;

{ Raise the interactive condition in the current ring.

      pmp$dispose_interactive_cond (condition_id);
    PROCEND raise_condition;
?? OLDTITLE ??
?? NEWTITLE := 'signal_job_synchronous_task', EJECT ??

{ NOTE: This request is only called by the job monitor task.

    PROCEDURE signal_job_synchronous_task
      (    signal: pmt$signal;
       VAR excuting_in_job_synch_task: boolean;
       VAR status: ost$status);

      VAR
        task_id: pmt$task_id,
        current_synchronous_gtid: ost$global_task_id;

      status.normal := TRUE;
      executing_in_job_synch_task := FALSE;

      clp$find_current_job_synch_task (task_id, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      pmp$get_global_task_id (task_id, current_synchronous_gtid, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      IF current_synchronous_gtid <> jmv$jcb.job_monitor_id THEN
        pmp$send_signal (current_synchronous_gtid, signal, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

      ELSE
        executing_in_job_synch_task := TRUE;
      IFEND;
    PROCEND signal_job_synchronous_task;
?? OLDTITLE ??
?? NEWTITLE := 'timesharing_block_exit_handler', EJECT ??

    PROCEDURE timesharing_block_exit_handler
      (    condition: pmt$condition;
           ignore_condition_information: ^pmt$condition_information;
           ignore_save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      raise_condition (timesharing_signal);
      handler_status.normal := TRUE;
    PROCEND timesharing_block_exit_handler;

?? OLDTITLE, EJECT ??


    timesharing_signal.signal := signal;

{ Check for special signals.

    check_for_special_signals (timesharing_signal, signal_processed, local_status);
    IF NOT local_status.normal THEN
      log_unexpected_status (local_status);
    IFEND;
    IF signal_processed THEN
      RETURN;
    IFEND;

{ Check to see if this is the job_monitor task.

    pmp$get_executing_task_gtid (executing_gtid);
    IF executing_gtid = jmv$jcb.job_monitor_id THEN

{ We only want to propogate the signal if the job is a timesharing or xterm job.

      IF NOT jmv$timesharing_job THEN
        IF NOT jmp$is_xterm_job () THEN
          log_unexpected_message ('Received a timesharing signal in a NON-timesharing job.');
          RETURN;
        IFEND;
      IFEND;

{ If the signal is disconnect - mark the job as disconnected (internally)

      IF (timesharing_signal.signal_contents.signal_kind = jmc$timesharing_disconnect) THEN

{ Mark the job as disconnected

        IF jmv$ts_job_disconnected THEN
          log_unexpected_message ('Received a disconnect signal in a disconnected job.');
          RETURN;
        IFEND;
        jmv$ts_job_disconnected := TRUE;

        statistic_data.statistic_id := jmc$ca_interactive_interval;
        jmp$emit_communication_stat (statistic_data);

        IF timesharing_signal.signal_contents.disconnect.disconnect_reason = jmc$ts_line_disconnect THEN

{ Call a network interface to indicate that the nominal connection has been disconnected

          nlp$record_nominal_disconnect (osc$timesharing_terminal_file, local_status);
          IF NOT local_status.normal THEN
            log_unexpected_status (local_status);
          IFEND;
        IFEND;
      IFEND;

{ Disable IO within all tasks in the job - except job monitor
{ Having gotten this far indicates that we should raise a condition within the current
{ job synchronous task.

      pmp$disable_ts_io_in_tasks;

{ Send a signal (if necessary) to the current job synchronous task.

      signal_job_synchronous_task (timesharing_signal.signal, executing_in_job_synch_task, local_status);
      IF NOT local_status.normal THEN
        signal_job_synchronous_task (timesharing_signal.signal, executing_in_job_synch_task, local_status);
        IF NOT local_status.normal THEN
          log_unexpected_message ('Couldn''t signal the current synchronous task.');
          log_unexpected_status (local_status);

{ If problems, raise the condition in the job monitor task

          executing_in_job_synch_task := TRUE;
        IFEND;
      IFEND;

{ If we are not the current job synchronous task then we are done.

      IF NOT executing_in_job_synch_task THEN
        RETURN;
      IFEND;
    IFEND;

{ The rest of the code contained in this signal handler is executed by the job's
{ current job synchronous task, i.e., the task that the user is talking to.

{ Establish a block exit handler in case we see a non-local exit.

    osp$establish_block_exit_hndlr (^timesharing_block_exit_handler);

{ Interrupt all terminal manager I/O requests.  This request may potentially be interrupted.
{ This signal handler may be invoked again by a disconnect or and reconnect request.  The
{ CDCNET connection is frozen by any synchronize requests so any further synchronize requests
{ will be "ignored" until the confirmation is sent to NAM/VE.

    iip$interrupt_timesharing_io (local_status);
    IF NOT local_status.normal THEN
      log_unexpected_status (local_status);
    IFEND;

{ Disestablish the block exit handler - the following operations do not require protection.

    osp$disestablish_cond_handler;

{ At this point, no tasks in the job have any active I/O requests and they can't start any.
{ This request determines the identity of the condition to be raised.  It also performs any
{ pre-condition processing that is necessary.  It then raises the condition in the task.

    raise_condition (timesharing_signal);

  PROCEND jmp$timesharing_signal_handler;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$validate_paired_connection', EJECT ??
*copy jmh$validate_paired_connection

  PROCEDURE [XDCL] jmp$validate_paired_connection
    (    unvalidated_connection_data_p: ^SEQ ( * );
     VAR login_family: ost$name;
     VAR login_user: ost$name;
     VAR system_job_name: jmt$system_supplied_name;
     VAR connection_request_kind: jmt$paired_connection_request;
     VAR status: ost$status);

    VAR
      job_status_count: jmt$job_status_count,
      job_status_options_p: ^jmt$job_status_options,
      job_status_results_keys_p: ^jmt$results_keys,
      job_status_results_seq_p: ^jmt$work_area,
      job_status_results_p: ^jmt$job_status_results,
      paired_connection_data_p: ^jmt$paired_connection_data,
      paired_connection_seq_p: ^SEQ ( * ),
      size_of_sequence: ost$segment_length,
      validation_options_p: ^jmt$user_validation_options;

    status.normal := TRUE;

    paired_connection_seq_p := unvalidated_connection_data_p;
    RESET paired_connection_seq_p;
    NEXT paired_connection_data_p IN paired_connection_seq_p;
    IF paired_connection_data_p = NIL THEN
      osp$set_status_condition (jme$invalid_paired_connection, status);
      RETURN;
    IFEND;

    IF (paired_connection_data_p^.connection_request <> jmc$pcr_attach_job_request) AND
          (paired_connection_data_p^.connection_request <> jmc$pcr_leveled_job_request) THEN
      osp$set_status_condition (jme$invalid_paired_connection, status);
      RETURN;
    IFEND;

    connection_request_kind := paired_connection_data_p^.connection_request;

    PUSH job_status_options_p: [1 .. 1];
    job_status_options_p^ [1].key := jmc$name_list;
    PUSH job_status_options_p^ [1].name_list: [1 .. 1];
    job_status_options_p^ [1].name_list^ [1].kind := jmc$system_supplied_name;
    IF (paired_connection_data_p^.connection_request = jmc$pcr_attach_job_request) THEN
      job_status_options_p^ [1].name_list^ [1].system_supplied_name :=
            paired_connection_data_p^.attach_job_request.system_job_name;
    ELSE {paired_connection_data_p^.connection_request = jmc$pcr_leveled_job_request
      job_status_options_p^ [1].name_list^ [1].system_supplied_name :=
            paired_connection_data_p^.leveled_job_request.system_job_name;
    IFEND;

    PUSH job_status_results_keys_p: [1 .. 2];
    job_status_results_keys_p^ [1] := jmc$login_family;
    job_status_results_keys_p^ [2] := jmc$login_user;

    jmp$get_result_size ({job_count} 1, #SEQ (job_status_results_keys_p^), size_of_sequence);
    PUSH job_status_results_seq_p: [[REP size_of_sequence OF cell]];
    RESET job_status_results_seq_p;
    jmp$get_job_status (job_status_options_p, job_status_results_keys_p, job_status_results_seq_p,
          job_status_results_p, job_status_count, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    PUSH validation_options_p: [1 .. 1];
    validation_options_p^ [1].key := jmc$encrypted_password;
    IF (paired_connection_data_p^.connection_request = jmc$pcr_attach_job_request) THEN
      validation_options_p^ [1].encrypted_password := paired_connection_data_p^.attach_job_request.
            encrypted_password;
    ELSE {paired_connection_data_p^.connection_request = jmc$pcr_leveled_job_request
      validation_options_p^ [1].encrypted_password := paired_connection_data_p^.leveled_job_request.
            encrypted_password;
    IFEND;

    jmp$validate_user (job_status_results_p^ [1]^ [1].login_family, job_status_results_p^ [1]^ [2].login_user,
          validation_options_p, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF (paired_connection_data_p^.connection_request = jmc$pcr_attach_job_request) THEN
      system_job_name := paired_connection_data_p^.attach_job_request.system_job_name;
    ELSE {paired_connection_data_p^.connection_request = jmc$pcr_leveled_job_request
      system_job_name := paired_connection_data_p^.leveled_job_request.system_job_name;
    IFEND;
    login_family := job_status_results_p^ [1]^ [1].login_family;
    login_user := job_status_results_p^ [1]^ [2].login_user;
  PROCEND jmp$validate_paired_connection;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL] jmp$clone_login', EJECT ??

  PROCEDURE [XDCL] jmp$clone_login
    (VAR status: ost$status);

    CONST
      paired_connect_timeout_interval = 120000; { in milliseconds

    VAR
      binary_mainframe_id: pmt$binary_mainframe_id,
      connection_attributes: ^nat$create_attributes,
      encrypted_password: ost$name,
      executing_job_name: jmt$system_supplied_name,
      get_attributes: array [1 .. 1] of nat$get_attribute,
      get_terminal_name: array [1 .. 1] of nat$accounting_data_field,
      ignore_status: ost$status,
      job_input_device: jmt$job_input_device,
      job_parameters: jmt$system_job_parameters,
      local_status: ost$status,
      paired_connection_data: jmt$paired_connection_data,
      peer_accounting_info: ^string ( * ),
      submit_variation: jmt$submit_job_variations,
      timesharing_title: ost$name,
      user_supplied_name: jmt$user_supplied_name;

    CONST
      acquire_timeout = 60,
      max_connections = 1;

    job_parameters := jmv$kjlx_p^ [jmv$jcb.job_id].system_label_p^.job_attributes.system_job_parameters;

    fmp$disconnect_for_clone (osc$timesharing_terminal_file, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    PUSH connection_attributes: [1 .. 2];
    connection_attributes^ [1].kind := nac$data_transfer_timeout;
    connection_attributes^ [1].data_transfer_timeout := nac$max_wait_time;
    connection_attributes^ [2].kind := nac$receive_wait_swapout;
    connection_attributes^ [2].receive_wait_swapout := TRUE;

{If there are no job parameters then the job is an initial submit
{otherwise the type of submit is encoded in the job parameters

    IF job_parameters.system_job_parameter_count = 0 THEN
      nap$attach_server_application (osc$timesharing, max_connections, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      nap$clone_connection (osc$timesharing, osc$timesharing_terminal_file, NIL, acquire_timeout, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      nap$change_attributes (osc$timesharing_terminal_file, connection_attributes^, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      nap$detach_server_application (osc$timesharing, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;

      nlp$register_nominal_connection (osc$timesharing_terminal_file, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    ELSE
      i#move (^job_parameters.system_job_parameter, ^submit_variation, #SIZE (submit_variation));
      IF submit_variation.kind = jmc$submit_detached_job THEN
        login_as_disconnected (status);
        RETURN;
      ELSEIF (submit_variation.kind = jmc$connection_switch) THEN
        jmp$initialize_timesharing (status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

      ELSEIF (submit_variation.kind = jmc$remote_connection_switch) THEN
        nap$attach_server_application (osc$timesharing, max_connections, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        nap$clone_connection (osc$timesharing, osc$timesharing_terminal_file, NIL, acquire_timeout, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        nap$change_attributes (osc$timesharing_terminal_file, connection_attributes^, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        nap$detach_server_application (osc$timesharing, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

        paired_connection_data.connection_request := jmc$pcr_leveled_job_results;
        paired_connection_data.leveled_job_results.successful := TRUE;

        iip$vtp_del_paired_con_first (#SEQ (paired_connection_data), local_status);
        IF NOT local_status.normal THEN
          log_unexpected_message ('clone_login - iip$vtp_del_paired_con_first failed with...');
          log_unexpected_status (local_status);
        IFEND;

        nlp$register_nominal_connection (osc$timesharing_terminal_file, status);
        IF NOT status.normal THEN
          RETURN;
        IFEND;

      ELSE

{Unknown type of submit request

        osp$system_error ('Unknown submit request', NIL);
      IFEND;
    IFEND;

{ Change the job mode to connected

    jmp$set_job_mode (jmc$interactive_connected, status);
    status.normal := TRUE;

{ Reset the Terminal_Name terminal attribute in the connection description and the
{ Job_Input_Device job attribute.

    get_attributes [1].kind := nac$peer_accounting_information;
    PUSH get_attributes [1].peer_accounting_information: [[REP 256 OF char]];
    nap$get_attributes (osc$timesharing_terminal_file, get_attributes, status);

    IF (status.normal) AND (get_attributes [1].peer_accounting_info_length <> 0) THEN
      RESET get_attributes [1].peer_accounting_information;
      NEXT peer_accounting_info: [get_attributes [1].peer_accounting_info_length] IN
            get_attributes [1].peer_accounting_information;

      job_input_device.size := get_attributes [1].peer_accounting_info_length;
      job_input_device.text := peer_accounting_info^;
      jmp$set_job_input_device (job_input_device);

      get_terminal_name [1].kind := nac$ca_device_name;
      nap$parse_accounting_data (peer_accounting_info, NIL, ^get_terminal_name, status);
      IF status.normal AND (get_terminal_name [1].kind = nac$ca_device_name) THEN
        iip$set_terminal_name (get_terminal_name [1].device_name);
      ELSE
        IF NOT status.normal THEN
          status.normal := TRUE;
        IFEND;
        iip$set_terminal_name (osc$null_name);
      IFEND;
    ELSE
      iip$set_terminal_name (osc$null_name);
    IFEND;

    iip$st_clone_connection (status);

  PROCEND jmp$clone_login;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$acquire_connection', EJECT ??
*copy jmh$acquire_connection

  PROCEDURE [XDCL, #GATE] jmp$acquire_connection
    (    server_name: ost$name;
     VAR service_data: jmt$service_data;
     VAR service_data_length: jmt$service_data_length;
     VAR status: ost$status);

    VAR
      connection_attributes: ^nat$create_attributes,
      get_attributes: array [1 .. 1] of nat$get_attribute,
      get_terminal_name: array [1 .. 1] of nat$accounting_data_field,
      ignore_status: ost$status,
      job_input_device: jmt$job_input_device,
      peer_accounting_info: ^string ( * ),
      timeout: nat$wait_time,
      terminal_attributes: array [1 .. 2] of ift$terminal_attribute;

    CONST
      max_connections = 1;


    nap$attach_server_application (server_name, max_connections, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ File must be marked as disconnected to acquire a new connection.  The
{ disconnect must occur after the nap$attach_server_application request in
{ case the caller specified an unknown server_name.

    fmp$disconnect_for_clone (osc$timesharing_terminal_file, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    nap$clone_connection (server_name, osc$timesharing_terminal_file, NIL, nac$max_wait_time, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    PUSH connection_attributes: [1 .. 2];
    connection_attributes^ [1].kind := nac$data_transfer_timeout;
    connection_attributes^ [1].data_transfer_timeout := nac$max_wait_time;
    connection_attributes^ [2].kind := nac$receive_wait_swapout;
    connection_attributes^ [2].receive_wait_swapout := TRUE;

    nap$change_attributes (osc$timesharing_terminal_file, connection_attributes^, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    nap$detach_server_application (server_name, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    nlp$register_nominal_connection (osc$timesharing_terminal_file, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{ Change the job mode to connected

    jmp$set_job_mode (jmc$interactive_connected, ignore_status);
    jmv$ts_job_disconnected := FALSE;
    pmp$enable_ts_io_in_tasks;
    status.normal := TRUE;

{ Reset the Terminal_Name terminal attribute in the connection description and the
{ Job_Input_Device job attribute.

    get_attributes [1].kind := nac$peer_accounting_information;
    PUSH get_attributes [1].peer_accounting_information: [[REP 256 OF char]];
    nap$get_attributes (osc$timesharing_terminal_file, get_attributes, status);

    IF (status.normal) AND (get_attributes [1].peer_accounting_info_length <> 0) THEN
      RESET get_attributes [1].peer_accounting_information;
      NEXT peer_accounting_info: [get_attributes [1].peer_accounting_info_length] IN
            get_attributes [1].peer_accounting_information;

      job_input_device.size := get_attributes [1].peer_accounting_info_length;
      job_input_device.text := peer_accounting_info^;
      jmp$set_job_input_device (job_input_device);

      get_terminal_name [1].kind := nac$ca_device_name;
      nap$parse_accounting_data (peer_accounting_info, NIL, ^get_terminal_name, status);
      IF status.normal AND (get_terminal_name [1].kind = nac$ca_device_name) THEN
        iip$set_terminal_name (get_terminal_name [1].device_name);
      ELSE
        status.normal := TRUE;
        iip$set_terminal_name (osc$null_name);
      IFEND;
    ELSE
      iip$set_terminal_name (osc$null_name);
    IFEND;

    iip$st_clone_connection (status);

    jmv$connection_acquired := TRUE;

{The following causes the new terminal attributes to be
{rippled thru open files

    terminal_attributes [1].key := ifc$page_width;
    terminal_attributes [2].key := ifc$page_length;
    ifp$get_terminal_attributes (clc$job_output, terminal_attributes, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    ifp$change_terminal_attributes (clc$job_output, terminal_attributes, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    get_attributes [1].kind := nac$peer_connect_data;
    PUSH get_attributes [1].peer_connect_data: [[REP 256 OF char]];
    nap$get_attributes (osc$timesharing_terminal_file, get_attributes, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    nap$get_connect_data (get_attributes [1].peer_connect_data, service_data, service_data_length, status);

  PROCEND jmp$acquire_connection;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$return_connection', EJECT ??
*copy jmh$return_connection

  PROCEDURE [XDCL, #GATE] jmp$return_connection
    (VAR status: ost$status);

?? NEWTITLE := 'handle_condition', EJECT ??

    PROCEDURE handle_condition
      (    condition: pmt$condition;
           condition_information: ^pmt$condition_information;
           stack_frame_save_area: ^ost$stack_frame_save_area;
       VAR handler_status: ost$status);

      IF condition.selector = ifc$interactive_condition THEN
        RETURN;
      ELSE
        pmp$continue_to_cause (pmc$execute_standard_procedure, handler_status);
      IFEND;

    PROCEND handle_condition;

?? OLDTITLE, EJECT ??

    VAR
      local_status: ost$status;

    IF NOT jmv$connection_acquired THEN
      RETURN;
    IFEND;

    osp$establish_condition_handler (^handle_condition, FALSE);

    nap$se_clear_request (osc$timesharing_terminal_file, status);

{ Note that the disconnect signal sent by the above call is sent to the
{ jobmonitor task.  This code is probably not running in the job monitor
{ task, so there will be a delay until the signal is processed by the jobmonitor
{ and the condition is sent back to this task......
{ (or this is not the job synch task and the condition will not come to this task)
{ The following call to long term wait allows the signal to be processed by
{ the jobmonitor task and the disconnect condition sent to this task and
{ be eaten by this procedures condition handler so that it will not be visible
{ to the caller(s).

    pmp$long_term_wait (2000, 2000);

{ Now you might say that the following call to nlp$record_nominal_disconnect
{ is not required because it will be called as a result of the disconnect
{ signal sent by nap$se_clear_request.  That is sometimes true.  And
{ sometimes not due to the signal processing described above.  This is a
{ failsafe call.

    nlp$record_nominal_disconnect (osc$timesharing_terminal_file, local_status);

    jmv$connection_acquired := FALSE;

  PROCEND jmp$return_connection;
?? OLDTITLE ??
?? NEWTITLE := 'login_as_disconnected', EJECT ??

{ This procedure initializes the timesharing environment for a job started
{ by jmp$submit_detached_job.
{ This procedure always runs in the job monitor task.

  PROCEDURE login_as_disconnected
    (VAR status: ost$status);

    IF (NOT syv$clone_enabled) OR (NOT syv$nosve_job_template) OR (NOT syv$job_initialization_complete) THEN
      fmp$create_network_file (osc$timesharing_terminal_file, nac$null_connection_id, nac$terminated, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;
    jmp$set_job_mode (jmc$interactive_sys_disconnect, status);
    jmv$initialized_as_disconnected := TRUE;
    jmv$connection_acquired := FALSE;
    jmv$ts_job_disconnected := TRUE;
    pmp$disable_ts_io_in_tasks;

  PROCEND login_as_disconnected;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] jmp$submit_detached_job', EJECT ??
*copy jmh$submit_detached_job

  PROCEDURE [XDCL, #GATE] jmp$submit_detached_job
    (    user_information: string ( * <= jmc$user_information_size);
     VAR status: ost$status);

    VAR
      capability: boolean,
      submitted_job_name: jmt$system_supplied_name,
      job_attribute_p: ^jmt$job_attribute_results,
      job_submission_options: ^jmt$job_submission_options,
      submit_variation: jmt$submit_job_variations;

    avp$get_capability (jmc$submit_detached_jobs, avc$user, capability, status);
    IF (NOT status.normal) OR (NOT capability) THEN
      osp$set_status_abnormal ('AV', ave$missing_required_capability, jmc$submit_detached_jobs, status);
      RETURN;
    IFEND;

    PUSH job_attribute_p: [1 .. 3];
    job_attribute_p^ [1].key := jmc$login_family;
    job_attribute_p^ [2].key := jmc$login_user;
    job_attribute_p^ [3].key := jmc$job_class;
    jmp$get_job_attributes (job_attribute_p, status);
    PUSH job_submission_options: [1 .. 9];
    job_submission_options^ [1].key := jmc$origin_application_name;
    job_submission_options^ [1].origin_application_name := osc$timesharing;
    job_submission_options^ [2].key := jmc$login_command_supplied;
    job_submission_options^ [2].login_command_supplied := FALSE;
    job_submission_options^ [3].key := jmc$login_family;
    job_submission_options^ [3].login_family := job_attribute_p^ [1].login_family;
    job_submission_options^ [4].key := jmc$login_user;
    job_submission_options^ [4].login_user := job_attribute_p^ [2].login_user;
    job_submission_options^ [5].key := jmc$immediate_init_candidate;
    job_submission_options^ [5].immediate_init_candidate := TRUE;
    job_submission_options^ [6].key := jmc$job_class;
    job_submission_options^ [6].job_class := job_attribute_p^ [3].job_class;
    job_submission_options^ [7].key := jmc$system_job_parameters;
    PUSH job_submission_options^ [7].system_job_parameters;
    submit_variation.kind := jmc$submit_detached_job;
    job_submission_options^ [7].system_job_parameters^.system_job_parameter_count := #SIZE (submit_variation);
    i#move (^submit_variation, ^job_submission_options^ [7].system_job_parameters^.system_job_parameter,
          #SIZE (submit_variation));
    job_submission_options^ [8].key := jmc$user_information;
    PUSH job_submission_options^ [8].user_information;
    job_submission_options^ [8].user_information^ := user_information;
    job_submission_options^ [9].key := jmc$job_destination_usage;
    job_submission_options^ [9].job_destination_usage := jmc$ve_local_usage;

    jmp$submit_job (clc$null_file, job_submission_options, submitted_job_name, status);

  PROCEND jmp$submit_detached_job;
?? OLDTITLE ??
MODEND jmm$timesharing_signal_handler;
