?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE File Server: Server: client_job_manager', EJECT ??
MODULE dfm$client_job_manager;

{
{  This server module manages the connection of client jobs to the server.
{  This involves registering and deleting the client job from the server,
{  and setting the clone's task private data to indicate the desired client job.
{  All client jobs for a single client mainframe are maintained in the
{  client job list, which is part of the client mainframe file.
{  This client job list contains enough information so that the
{  clone tasks may run on behalf of the client job.
{

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc dfd$driver_queue_types
*copyc dfd$request_package
*copyc dfe$error_condition_codes
*copyc dfi$console_display
*copyc dfi$display
*copyc dfi$log_display
*copyc dft$change_client_job_validaton
*copyc dft$delete_client_job
*copyc dft$display_identifier
*copyc dft$end_job_recovery
*copyc dft$entry_type
*copyc dft$establish_client_job
*copyc dft$queue_index
*copyc dft$rpc_served_job_list
*copyc dft$start_job_recovery
*copyc dpt$window_id
*copyc i#current_sequence_position
*copyc osd$integer_limits
*copyc ost$caller_identifier
?? POP ??
*copyc amp$return
*copyc clp$get_value
*copyc clp$scan_parameter_list
*copyc dfp$acquire_client_mf_file
*copyc dfp$crack_mainframe_id
*copyc dfp$display
*copyc dfp$verify_system_administrator
*copyc dfp$word_boundary
*copyc mmp$close_segment
*copyc osp$append_status_integer
*copyc osp$clear_signature_lock
*copyc osp$decrement_locked_variable
*copyc osp$increment_locked_variable
*copyc osp$initialize_signature_lock
*copyc osp$reset_heap
*copyc osp$set_signature_lock
*copyc osp$set_status_abnormal
*copyc osp$system_error
*copyc pfp$complete_job_recovery
*copyc pfp$detach_all_catalogs
*copyc pfp$process_job_end
*copyc pfp$reset_task_environment
*copyc pfp$setup_attached_pf_recovery
*copyc pfp$set_task_environment
*copyc pmp$get_pseudo_mainframe_id
*copyc qfp$server_job_end
*copyc syp$invoke_system_debugger

*copyc dft$client_job_list
*copyc dfv$file_server_debug_enabled
*copyc jmv$system_job_ssn

?? TITLE := 'Global Declarations Declared by This Module', EJECT ??
?? EJECT ??
*copyc dfv$p_client_mainframe_file

?? TITLE := '[XDCL] dfp$change_client_job_validaton ', EJECT ??

{
{   The purpose of this request is to change the client job environment
{ on the server to have the new validation information.  Subsequent requests
{ to the server will use this validation information.

  PROCEDURE [XDCL] dfp$change_client_job_validaton
    (VAR p_param_received_from_client {Input} : dft$p_receive_parameters;
     VAR p_data_from_client {Input} : dft$p_receive_data;
     VAR p_send_to_client_params {^Output} : dft$p_send_parameters;
     VAR p_data_to_client {^Output} : dft$p_send_data;
     VAR send_parameters_length: dft$send_parameter_size;
     VAR data_size_to_send_to_client: dft$send_data_size;
     VAR status: ost$status);

    VAR
      client_job_id: dft$client_job_id,
      p_client_job_space: ^dft$client_job_space,
      p_parameters: ^dft$change_client_job_valid_in;

    status.normal := TRUE;
    send_parameters_length := 0;
    data_size_to_send_to_client := 0;
    NEXT p_parameters IN p_param_received_from_client;
    client_job_id := p_parameters^.client_job_id;
    dfp$validate_client_job_id (client_job_id, p_parameters^.system_supplied_job_name,
          dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    p_client_job_space := dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root.
          p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          p_client_job_list^ [client_job_id.job_list_index].p_client_job_space;

{ Remove all the previously queued catalogs, so the new account and project are used.

    pfp$detach_all_catalogs;
    p_client_job_space^.account := p_parameters^.account;
    p_client_job_space^.project := p_parameters^.project;

  PROCEND dfp$change_client_job_validaton;
?? TITLE := '[XDCL] dfp$delete_client_job ', EJECT ??

{
{   The purpose of this request is to remove the client job environment
{ from the server.  All permanent files left attached are detached.
{ All tables on the server associated with the client job are deleted.
{

  PROCEDURE [XDCL] dfp$delete_client_job
    (VAR p_param_received_from_client {Input} : dft$p_receive_parameters;
     VAR p_data_from_client {Input} : dft$p_receive_data;
     VAR p_send_to_client_params {^Output} : dft$p_send_parameters;
     VAR p_data_to_client {^Output} : dft$p_send_data;
     VAR send_parameters_length: dft$send_parameter_size;
     VAR data_size_to_send_to_client: dft$send_data_size;
     VAR status: ost$status);

    VAR
      client_job_id: dft$client_job_id,
      host_binary_mainframe_id: pmt$binary_mainframe_id,
      p_parameters: ^dft$delete_client_job_inp;

    status.normal := TRUE;
    send_parameters_length := 0;
    data_size_to_send_to_client := 0;
    NEXT p_parameters IN p_param_received_from_client;

    IF p_parameters^.job_is_leveled THEN
      pmp$get_pseudo_mainframe_id (host_binary_mainframe_id);
      IF host_binary_mainframe_id = p_parameters^.job_end_info.server_mainframe_id THEN
        qfp$server_job_end (p_parameters^.job_end_info);
      IFEND;
    IFEND;

    IF p_parameters^.client_job_table_exists THEN
      remove_client_job (dfv$p_client_mainframe_file, p_parameters^.client_job_id, status);
    IFEND;

  PROCEND dfp$delete_client_job;
?? TITLE := '[XDCL] dfp$display_client_jobs ', EJECT ??
{ This display is of the form
{  123456789A123456789B123456789C123456789D123456789E123456789F123456789G123456789H1
{ '--SYSTEM SUPPLIED NAME----USER JOB NAME-------------TRANSACTIONS--ACCESS-------'
{
  PROCEDURE [XDCL] dfp$display_client_jobs
    (    p_client_mainframe_file: dft$p_mainframe_file;
     VAR display_identifier: dft$display_identifier;
     VAR status: ost$status);

    VAR
      active_pointer: integer,
      display_string: string (80),
      job_list_entry: dft$client_job_list_entry,
      job_list_index: 1 .. dfc$client_job_list_size,
      length: integer,
      local_status: ost$status;

    osp$set_signature_lock (p_client_mainframe_file^.mainframe_header.client_job_list_lock, osc$wait, status);


  /for_all_job_lists/
    FOR active_pointer := 1 TO p_client_mainframe_file^.mainframe_header.client_job_list_root.
          number_of_active_pointers DO

    /locate_active_job/
      FOR job_list_index := 1 TO dfc$client_job_list_size DO
        IF p_client_mainframe_file^.mainframe_header.client_job_list_root.
              p_job_list_pointer_array^ [active_pointer].assignment (job_list_index) =
              dfc$assigned_entry_char THEN
          job_list_entry := p_client_mainframe_file^.mainframe_header.client_job_list_root.
                p_job_list_pointer_array^ [active_pointer].p_client_job_list^ [job_list_index];
          display_string := ' ';
          display_string (3, * ) := job_list_entry.system_supplied_job_name;
          display_string (26, * ) := job_list_entry.user_supplied_job_name;
          IF job_list_entry.recovering THEN
            display_string (57, * ) := 'RECOVERING';
          ELSEIF job_list_entry.job_lifetime <> p_client_mainframe_file^.mainframe_header.server_lifetime THEN
            display_string (57, * ) := 'AWAIT REC';
          ELSE
            STRINGREP (display_string (57, 7), length, job_list_entry.request_count: 7);
          IFEND;
          IF job_list_entry.p_client_job_space^.family_access_kind = dfc$remote_file_access THEN
            display_string (68, 7) := 'FILE';
          ELSEIF job_list_entry.p_client_job_space^.family_access_kind = dfc$remote_login_access THEN
            display_string (68, 7) := 'LOGIN ';
          ELSEIF job_list_entry.p_client_job_space^.family_access_kind = dfc$job_leveling_access THEN
            display_string (68, 7) := 'LEVELED';
          IFEND;
          IF job_list_entry.job_mode = jmc$batch THEN
            display_string (78) := 'B';
          ELSE { interactive
            display_string (78) := 'I';
          IFEND;
          dfp$display (display_string, display_identifier, status);

        IFEND;
      FOREND /locate_active_job/;
    FOREND /for_all_job_lists/;
    osp$clear_signature_lock (p_client_mainframe_file^.mainframe_header.client_job_list_lock, local_status);


  PROCEND dfp$display_client_jobs;
?? TITLE := '[XDCL] dfp$end_client_job_recovery ', EJECT ??

{
{   The purpose of this request is to complete the recovery sequence for
{ a client job.  This is performed at the end of the server job recovery.
{ This routine involves verifying that the client has relinked all server files
{ and then advances the lifetime of the job.
{

  PROCEDURE [XDCL] dfp$end_client_job_recovery
    (VAR p_param_received_from_client {Input} : dft$p_receive_parameters;
     VAR p_data_from_client {Input} : dft$p_receive_data;
     VAR p_send_to_client_params {^Output} : dft$p_send_parameters;
     VAR p_data_to_client {^Output} : dft$p_send_data;
     VAR send_parameters_length: dft$send_parameter_size;
     VAR data_size_to_send_to_client: dft$send_data_size;
     VAR status: ost$status);

    VAR
      client_job_id: dft$client_job_id,
      host_binary_mainframe_id: pmt$binary_mainframe_id,
      ignore_status: ost$status,
      p_client_job_space: ^dft$client_job_space,
      p_end_job_recovery_params: ^dft$end_job_recovery;

    status.normal := TRUE;
    send_parameters_length := 0;
    data_size_to_send_to_client := 0;
    NEXT p_end_job_recovery_params IN p_param_received_from_client;

    client_job_id := p_end_job_recovery_params^.client_job_id;
    p_client_job_space := dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root.
          p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          p_client_job_list^ [client_job_id.job_list_index].p_client_job_space;
    dfp$set_client_job_environment (client_job_id, { system administrator } TRUE,
          { family administrator } TRUE, status);
    IF NOT status.normal THEN

{ Terminate the job? Remove it from the file? Detach files?

      RETURN;
    IFEND;
    pfp$complete_job_recovery (dfv$p_client_mainframe_file^.mainframe_header.client_mainframe_id, status);

{ Advance the jobs lifetime

    dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root.
          p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          p_client_job_list^ [client_job_id.job_list_index].job_lifetime :=
          p_end_job_recovery_params^.server_lifetime;
    dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root.
          p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          p_client_job_list^ [client_job_id.job_list_index].recovering := FALSE;
  PROCEND dfp$end_client_job_recovery;
?? TITLE := '[XDCL] dfp$establish_client_job ', EJECT ??

{
{   The purpose of this request is to initially establish the connection
{   between a job on the client, and the file server.  As a result of this
{   request a partial job environment is established on the server.  This
{   job environment is used on subsequent requests from the client.
{

  PROCEDURE [XDCL] dfp$establish_client_job
    (VAR p_param_received_from_client {Input} : dft$p_receive_parameters;
     VAR p_data_from_client {Input} : dft$p_receive_data;
     VAR p_send_to_client_params {^Output} : dft$p_send_parameters;
     VAR p_data_to_client {^Output} : dft$p_send_data;
     VAR send_parameters_length: dft$send_parameter_size;
     VAR data_size_to_send_to_client: dft$send_data_size;
     VAR status: ost$status);

    VAR
      client_job_id: dft$client_job_id,
      p_parameters: ^dft$establish_client_job_inp;

    send_parameters_length := 0;
    data_size_to_send_to_client := 0;
    status.normal := TRUE;
    NEXT p_parameters IN p_param_received_from_client;

    IF dfv$file_server_debug_enabled THEN
      display (' Establish client job ');
      display_bytes (p_parameters, #SIZE (p_parameters^));
    IFEND;

    dfp$register_client_job (p_parameters^.user_id, p_parameters^.account, p_parameters^.project,
          p_parameters^.system_supplied_job_name, p_parameters^.user_supplied_job_name,
          p_parameters^.job_mode, p_parameters^.family_access_kind, p_parameters^.job_lifetime,
          dfv$p_client_mainframe_file, client_job_id, status);

    IF status.normal THEN
      build_job_begin_vars (client_job_id, p_send_to_client_params, send_parameters_length);
    ELSEIF (status.condition = dfe$client_job_registered) AND (p_parameters^.forced_reconnection OR
     (p_parameters^.system_supplied_job_name = jmv$system_job_ssn { Needs analysis - Kludge})) THEN
      { Remove the old job, and re-establish the job under a new lifetime.
      IF dfv$file_server_debug_enabled THEN
        display (' Forced reconnection ');
        display (p_parameters^.system_supplied_job_name);
      IFEND;
      dfp$set_client_job_environment (client_job_id, { system administrator } TRUE,
            { family administrator } TRUE, status);
      remove_client_job (dfv$p_client_mainframe_file, client_job_id, status);
      IF status.normal THEN
        dfp$register_client_job (p_parameters^.user_id, p_parameters^.account, p_parameters^.project,
              p_parameters^.system_supplied_job_name, p_parameters^.user_supplied_job_name,
              p_parameters^.job_mode, p_parameters^.family_access_kind, p_parameters^.job_lifetime,
              dfv$p_client_mainframe_file, client_job_id, status);
        IF status.normal THEN
          build_job_begin_vars (client_job_id, p_send_to_client_params, send_parameters_length);
        IFEND;
      IFEND;
    IFEND;
  PROCEND dfp$establish_client_job;
?? TITLE := '[XDCL] dfp$get_client_job_list ', EJECT ??

  PROCEDURE [XDCL] dfp$get_client_job_list
    (VAR p_param_received_from_client {Input} : dft$p_receive_parameters;
     VAR p_data_from_client {Input} : dft$p_receive_data;
     VAR p_send_to_client_params {^Output} : dft$p_send_parameters;
     VAR p_data_to_client {^Output} : dft$p_send_data;
     VAR send_parameters_length: dft$send_parameter_size;
     VAR data_size_to_send_to_client: dft$send_data_size;
     VAR status: ost$status);

    VAR
      job_list_entry: dft$client_job_list_entry,
      job_list_index: dft$client_job_list_index,
      job_list_pointer_index: dft$job_list_ptr_array_index,
      log_string: string (80),
      log_string_length: integer,
      p_job_list_pointer: ^dft$job_list_pointer_array,
      p_served_job_list_data: ^dft$rpc_served_job_list_data,
      p_served_job_list_header: ^dft$rpc_served_job_list_header;

    status.normal := TRUE;

    NEXT p_served_job_list_header IN p_data_to_client;
    p_served_job_list_header^.number_of_jobs := 0;
    p_served_job_list_header^.number_of_jobs_awaiting_rec := 0;

    p_job_list_pointer := dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root.
          p_job_list_pointer_array;

  /search_mainframe_file/
    FOR job_list_pointer_index := 1 TO dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root.
          number_of_active_pointers DO

    /find_active_jobs/
      FOR job_list_index := 1 TO dfc$client_job_list_size DO
        IF p_job_list_pointer^ [job_list_pointer_index].assignment (job_list_index) = dfc$free_entry_char THEN
          CYCLE /find_active_jobs/;
        IFEND;
        job_list_entry := p_job_list_pointer^ [job_list_pointer_index].p_client_job_list^ [job_list_index];
        IF job_list_entry.job_lifetime <> dfv$p_client_mainframe_file^.mainframe_header.server_lifetime THEN
          p_served_job_list_header^.number_of_jobs_awaiting_rec :=
                p_served_job_list_header^.number_of_jobs_awaiting_rec + 1;
        IFEND;

        NEXT p_served_job_list_data IN p_data_to_client;
        p_served_job_list_data^.system_supplied_job_name := job_list_entry.system_supplied_job_name;
        p_served_job_list_data^.client_job_id.job_list_pointer_index := job_list_pointer_index;
        p_served_job_list_data^.client_job_id.job_list_index := job_list_index;

        p_served_job_list_header^.number_of_jobs := p_served_job_list_header^.number_of_jobs + 1;

      FOREND /find_active_jobs/;

    FOREND /search_mainframe_file/;

    data_size_to_send_to_client := i#current_sequence_position (p_data_to_client);
    send_parameters_length := 0;
    STRINGREP (log_string, log_string_length, ' Client ',
     dfv$p_client_mainframe_file^.mainframe_header.client_mainframe_name,
     ' Total_jobs:',  p_served_job_list_header^.number_of_jobs,
     '   Awaiting_recovery:', p_served_job_list_header^.number_of_jobs_awaiting_rec);
    log_display ($pmt$ascii_logset[pmc$system_log], log_string (1, log_string_length));
    IF dfv$file_server_debug_enabled THEN
      display (log_string (1, log_string_length));
      display_to_console (log_string (1, log_string_length));
    IFEND;

  PROCEND dfp$get_client_job_list;
?? TITLE := '[XDCL] dfp$pop_job_unrecoverable ', EJECT ??

  PROCEDURE [XDCL] dfp$pop_job_unrecoverable
    (    client_job_id: dft$client_job_id);

    CONST
      initial_value = 0;

    VAR
      actual_value: integer,
      error: boolean,
      status: ost$status;

    osp$decrement_locked_variable (dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root.
          p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          p_client_job_list^ [client_job_id.job_list_index].inhibit_job_recovery, initial_value, actual_value,
          error);
    IF error AND dfv$file_server_debug_enabled THEN
      syp$invoke_system_debugger (' INHIBIT JOB RECOVERY CONFLICT ', 0, status);
    IFEND;
  PROCEND dfp$pop_job_unrecoverable;
?? TITLE := '[XDCL] dfp$push_job_unrecoverable ', EJECT ??

  PROCEDURE [XDCL] dfp$push_job_unrecoverable
    (    client_job_id: dft$client_job_id);

    CONST
      initial_value = 0;

    VAR
      actual_value: integer;

    osp$increment_locked_variable (dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root.
          p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          p_client_job_list^ [client_job_id.job_list_index].inhibit_job_recovery, initial_value,
          actual_value);
  PROCEND dfp$push_job_unrecoverable;

?? TITLE := '[XDCL] dfp$register_client_job ', EJECT ??

  PROCEDURE [XDCL] dfp$register_client_job
    (    user_id: ost$user_identification;
         account_name: avt$account_name;
         project_name: avt$project_name;
         system_supplied_job_name: jmt$system_supplied_name;
         user_supplied_job_name: jmt$user_supplied_name;
         job_mode: jmt$Job_mode;
         family_access_kind: dft$family_access_kinds;
         job_lifetime: dft$lifetime;
         p_client_mainframe_file: ^dft$client_mainframe_file;
     VAR client_job_id: dft$client_job_id;
     VAR status: ost$status);

    VAR
      client_job_found: boolean,
      local_status: ost$status;

    osp$set_signature_lock (p_client_mainframe_file^.mainframe_header.client_job_list_lock, osc$wait, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    locate_client_job (system_supplied_job_name, p_client_mainframe_file^.mainframe_header.
          client_job_list_root, client_job_id, client_job_found);
    IF client_job_found THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$client_job_registered, system_supplied_job_name,
            status);
    IFEND;

    IF status.normal THEN
      get_free_client_job_table_entry (p_client_mainframe_file^.mainframe_header.client_job_list_root,
            p_client_mainframe_file^.mainframe_heap, client_job_id, status);
    IFEND;

    IF status.normal THEN
      create_client_job_environment (user_id, account_name, project_name, system_supplied_job_name,
            user_supplied_job_name, job_mode, family_access_kind, job_lifetime,
            p_client_mainframe_file^.mainframe_header.client_job_list_root.
            p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
            p_client_job_list^ [client_job_id.job_list_index], p_client_mainframe_file^.mainframe_heap);

      p_client_mainframe_file^.mainframe_header.client_job_list_root.
            p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
            assignment (client_job_id.job_list_index) := dfc$assigned_entry_char;
    IFEND;


    osp$clear_signature_lock (p_client_mainframe_file^.mainframe_header.client_job_list_lock, local_status);
    IF status.normal AND NOT local_status.normal THEN
      status := local_status;
    IFEND;
  PROCEND dfp$register_client_job;

?? TITLE := '[XDCL] dfp$remove_unknown_jobs ', EJECT ??
{   The purpuse of this request is to remove any requested job from the
{ client mainframe file.  The client mainframe supplies the list of jobs and the
{ client_job_id for each requested job.  The list of jobs was first gotton
{ by calling dfp$get_client_job_list, and is really just the list of these
{ jobs that no longer exist on the client mainframe .
{ All attached permanent files for the jobs are removed.
{
  PROCEDURE [XDCL] dfp$remove_unknown_jobs
    (VAR p_param_received_from_client {Input} : dft$p_receive_parameters;
     VAR p_data_from_client {Input} : dft$p_receive_data;
     VAR p_send_to_client_params {^Output} : dft$p_send_parameters;
     VAR p_data_to_client {^Output} : dft$p_send_data;
     VAR send_parameters_length: dft$send_parameter_size;
     VAR data_size_to_send_to_client: dft$send_data_size;
     VAR status: ost$status);

    VAR
      job: ost$non_negative_integers,
      log_string: string (80),
      log_string_length: integer,
      p_job_list_pointer: ^dft$job_list_pointer_array,
      p_served_job_list_data: ^dft$rpc_served_job_list_data,
      p_served_job_list_header: ^dft$rpc_served_job_list_header,
      valid_client_job_id: boolean;

    status.normal := TRUE;
    send_parameters_length := 0;
    data_size_to_send_to_client := 0;

    p_job_list_pointer := dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root.
          p_job_list_pointer_array;

    NEXT p_served_job_list_header IN p_data_from_client;
    STRINGREP (log_string, log_string_length, ' Client ',
      dfv$p_client_mainframe_file^.mainframe_header.client_mainframe_name,
      ' Removing jobs:',  p_served_job_list_header^.number_of_jobs);
    log_display ($pmt$ascii_logset[pmc$system_log], log_string (1, log_string_length));
    IF dfv$file_server_debug_enabled THEN
      display (log_string (1, log_string_length));
      display_to_console (log_string (1, log_string_length));
    IFEND;

  /check_jobs/
    FOR job := 1 TO p_served_job_list_header^.number_of_jobs DO
      NEXT p_served_job_list_data IN p_data_from_client;

      dfp$validate_client_job_id (p_served_job_list_data^.client_job_id,
            p_served_job_list_data^.system_supplied_job_name,
            dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root, status);
      valid_client_job_id := status.normal;
      IF valid_client_job_id THEN
        IF dfv$file_server_debug_enabled THEN
         display_integer (' dfp$remove_unknown_jobs: job_list_pointer_index=',
               p_served_job_list_data^.client_job_id.job_list_pointer_index);
         display_integer ('                          job_list_index=',
               p_served_job_list_data^.client_job_id.job_list_index);
         display (p_served_job_list_data^.system_supplied_job_name);
         log_display ($pmt$ascii_logset[pmc$system_log],
               p_served_job_list_data^.system_supplied_job_name);
        IFEND;
      { Make the task look like its running on behalf of the user job
        dfp$set_client_job_environment (p_served_job_list_data^.client_job_id, {system_administrator} TRUE,
              {family_administrator} TRUE, status);
        remove_client_job (dfv$p_client_mainframe_file, p_served_job_list_data^.client_job_id, status);
      IFEND;

    FOREND /check_jobs/;

    status.normal := TRUE;


    pfp$reset_task_environment;

  PROCEND dfp$remove_unknown_jobs;
?? TITLE := '[XDCL] dfp$set_client_job_environment ', EJECT ??

{ The module is HIGHLY COUPLED with module PFM$TASK_PRIVATE_DATA

  PROCEDURE [XDCL] dfp$set_client_job_environment
    (    client_job_id: dft$client_job_id;
         system_administrator: boolean;
         family_administrator: boolean;
     VAR status: ost$status);

    VAR
      p_client_job_space: ^dft$client_job_space;

    p_client_job_space := dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root.
          p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          p_client_job_list^ [client_job_id.job_list_index].p_client_job_space;
    dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root.
          p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          p_client_job_list^ [client_job_id.job_list_index].request_count :=
          dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root.
          p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          p_client_job_list^ [client_job_id.job_list_index].request_count + 1;

    pfp$set_task_environment (p_client_job_space, system_administrator, family_administrator);
    status.normal := TRUE;

  PROCEND dfp$set_client_job_environment;

?? TITLE := '[XDCL] dfp$start_client_job_recovery ', EJECT ??

{
{   The purpose of this request is to initiate the recovery sequence for
{ a client job.  This is performed at the start of the server job recovery.
{ This routine involves a minimal verification of the client job
{ registration in the client mainframe file, and then a marking of all
{ attached permanent files as awaiting recovery.
{

  PROCEDURE [XDCL] dfp$start_client_job_recovery
    (VAR p_param_received_from_client {Input} : dft$p_receive_parameters;
     VAR p_data_from_client {Input} : dft$p_receive_data;
     VAR p_send_to_client_params {^Output} : dft$p_send_parameters;
     VAR p_data_to_client {^Output} : dft$p_send_data;
     VAR send_parameters_length: dft$send_parameter_size;
     VAR data_size_to_send_to_client: dft$send_data_size;
     VAR status: ost$status);

    VAR
      client_job_found: boolean,
      client_job_id: dft$client_job_id,
      p_client_job_space: ^dft$client_job_space,
      host_binary_mainframe_id: pmt$binary_mainframe_id,
      p_start_job_recovery_out: ^dft$start_job_recovery_out,
      p_start_job_recovery_params: ^dft$start_job_recovery_in;

    status.normal := TRUE;
    send_parameters_length := 0;
    data_size_to_send_to_client := 0;
    NEXT p_start_job_recovery_params IN p_param_received_from_client;

    locate_client_job (p_start_job_recovery_params^.system_supplied_job_name,
          dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root, client_job_id,
          client_job_found);
    IF client_job_found THEN
      NEXT p_start_job_recovery_out IN p_send_to_client_params;
      send_parameters_length := #SIZE (p_start_job_recovery_out^);
      p_start_job_recovery_out^.client_job_id := client_job_id;
      dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root.
            p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
            p_client_job_list^ [client_job_id.job_list_index].recovering := TRUE;
      p_client_job_space := dfv$p_client_mainframe_file^.mainframe_header.client_job_list_root.
            p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
            p_client_job_list^ [client_job_id.job_list_index].p_client_job_space;
      dfp$set_client_job_environment (client_job_id, { system administrator } TRUE,
            { family administrator } TRUE, status);
      IF NOT status.normal THEN

{ Terminate the job? Remove it from the file? Detach files?

        RETURN;
      IFEND;
      pfp$setup_attached_pf_recovery (pfc$attached_pf_awaiting_client, status);
    ELSE
      osp$set_status_abnormal (dfc$file_server_id, dfe$bad_client_job_id,
            ' unknown system job name - start jr ', status);
    IFEND;
  PROCEND dfp$start_client_job_recovery;
?? TITLE := '[XDCL, #GATE] dfp$terminate_client_job ', EJECT ??
{
{    The purpose of this request is to provide for removing a client job from
{ the client mainframe file that exists on the server mainframe.  This
{ subcommand may only be issued on the server mainframe.  This causes the job
{ to be removed and to detach all server files that the client job had
{ attached.
{
{    This subcommand may only be issued when the server-to-client connection is
{ in an awaiting_recovery state or when the job has not yet recovered (that
{ is the server is active or inactive but the jobs lifetime is less than that
{ of ths server).
{ Only when the job is awaiting recovery does
{ the job on the client re-verifies that the job is still registered on the
{ server mainframe.  If the job is no longer registered (for example because of
{ this subcommand) all server files that the job on the client is using are
{ marked as terminated.
{
{    This subcommand is currently only provided for testing purposes.  To
{ exernalize it some of the error messages might need to be cleaned up.  To
{ allow the job in the inactive state some verification would have to be done
{ when the job first detected that the server was active.
{

  PROCEDURE [XDCL, #GATE] dfp$terminate_client_job
    (    parameter_list: clt$parameter_list;
     VAR status: ost$status);

{  pdt tercj_pdt (
{   client_mainframe_id, cmid: name 17 = $required
{   system_job_name, sjn: name 19 = $required
{   status)

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

  VAR
    tercj_pdt: [STATIC, READ, cls$pdt] clt$parameter_descriptor_table := [^tercj_pdt_names, ^tercj_pdt_params
  ];

  VAR
    tercj_pdt_names: [STATIC, READ, cls$pdt_names_and_defaults] array [1 .. 5] of
  clt$parameter_name_descriptor := [['CLIENT_MAINFRAME_ID', 1], ['CMID', 1], ['SYSTEM_JOB_NAME', 2], ['SJN', 2
  ], ['STATUS', 3]];

  VAR
    tercj_pdt_params: [STATIC, READ, cls$pdt_parameters] array [1 .. 3] of clt$parameter_descriptor := [

{ CLIENT_MAINFRAME_ID CMID }
    [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 17, 17]],

{ SYSTEM_JOB_NAME SJN }
    [[clc$required], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$name_value, 19, 19]],

{ STATUS }
    [[clc$optional], 1, 1, 1, 1, clc$value_range_not_allowed, [NIL, clc$variable_reference,
  clc$array_not_allowed, clc$status_value]]];

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

    VAR
      caller_id: ost$caller_identifier,
      client_job_found: boolean,
      client_job_id: dft$client_job_id,
      client_mainframe: pmt$mainframe_id,
      client_mainframe_id: pmt$binary_mainframe_id,
      client_mainframe_lfn: ost$name,
      client_segment_pointer: mmt$segment_pointer,
      local_status: ost$status,
      p_client_job_entry: ^dft$client_job_list_entry,
      p_client_mainframe_file: dft$p_mainframe_file,
      system_supplied_job_name: jmt$system_supplied_name,
      value: clt$value;

    #CALLER_ID (caller_id);
    clp$scan_parameter_list (parameter_list, tercj_pdt, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    dfp$verify_system_administrator ('TERMINATE_CLIENT_JOB', status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    dfp$crack_mainframe_id ('CLIENT_MAINFRAME_ID', client_mainframe, client_mainframe_id, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    clp$get_value ('SYSTEM_JOB_NAME', 1, 1, clc$low, value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    system_supplied_job_name := value.name.value;

    dfp$acquire_client_mf_file (client_mainframe, {read_only} FALSE, client_mainframe_lfn,
          client_segment_pointer, p_client_mainframe_file, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    osp$set_signature_lock (p_client_mainframe_file^.mainframe_header.client_job_list_lock, osc$wait, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    locate_client_job (system_supplied_job_name, p_client_mainframe_file^.mainframe_header.
          client_job_list_root, client_job_id, client_job_found);
    IF NOT client_job_found THEN
      osp$clear_signature_lock (p_client_mainframe_file^.mainframe_header.client_job_list_lock, status);
      mmp$close_segment (client_segment_pointer, caller_id.ring, local_status);
      amp$return (client_mainframe_lfn, local_status);
      osp$set_status_abnormal (dfc$file_server_id, dfe$bad_client_job_id, ' Unknown system_job_name ',
            status);
      RETURN;
    IFEND;

    p_client_job_entry :=  ^p_client_mainframe_file^.mainframe_header.client_job_list_root.
          p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          p_client_job_list^ [client_job_id.job_list_index];
    IF (p_client_mainframe_file^.mainframe_header.server_state <> dfc$awaiting_recovery) AND
          (p_client_job_entry^.recovering OR (p_client_job_entry^.job_lifetime =
           p_client_mainframe_file^.mainframe_header.server_lifetime)) THEN
      osp$clear_signature_lock (p_client_mainframe_file^.mainframe_header.client_job_list_lock, status);
      mmp$close_segment (client_segment_pointer, caller_id.ring, local_status);
      amp$return (client_mainframe_lfn, local_status);
      osp$set_status_abnormal (dfc$file_server_id, dfe$client_active, 'job must be awaiting_recovery ',
            status);
      RETURN;
    IFEND;

    pfp$set_task_environment (p_client_job_entry^.p_client_job_space, { system_administrator} TRUE,
        { family_administrator} TRUE);

    osp$clear_signature_lock (p_client_mainframe_file^.mainframe_header.client_job_list_lock, status);
    remove_client_job (p_client_mainframe_file, client_job_id, status);

    pfp$reset_task_environment;
    mmp$close_segment (client_segment_pointer, caller_id.ring, local_status);
    amp$return (client_mainframe_lfn, local_status);
  PROCEND dfp$terminate_client_job;
?? TITLE := '[XDCL] dfp$validate_client_job_id ', EJECT ??

  PROCEDURE [XDCL] dfp$validate_client_job_id
    (    client_job_id: dft$client_job_id;
         system_supplied_job_name: jmt$system_supplied_name;
         client_job_list_root: dft$client_job_list_root;
     VAR status: ost$status);

    IF client_job_id.job_list_pointer_index > client_job_list_root.number_of_active_pointers THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$bad_client_job_id, ' job_list_pointer_index ', status);
      RETURN;
    IFEND;

    IF client_job_id.job_list_index > #SIZE (client_job_list_root.
          p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].assignment) THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$bad_client_job_id, ' job_list_index size ', status);
      RETURN;
    IFEND;

    IF client_job_list_root.p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          assignment (client_job_id.job_list_index) <> dfc$assigned_entry_char THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$bad_client_job_id, ' job_list_index free', status);
      RETURN;
    IFEND;

    IF client_job_list_root.p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          p_client_job_list^ [client_job_id.job_list_index].system_supplied_job_name <>
          system_supplied_job_name THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$bad_client_job_id, ' system_supplied_job_name ',
            status);
      RETURN;
    IFEND;
    status.normal := TRUE;
  PROCEND dfp$validate_client_job_id;
?? TITLE := '[INLINE] build_job_begin_vars  ', EJECT ??

  PROCEDURE [INLINE] build_job_begin_vars
    (    client_job_id: dft$client_job_id;
     VAR p_send_parameters: dft$p_send_parameters;
     VAR send_parameters_size: dft$send_parameter_size);

    VAR
      p_client_job_id: ^dft$client_job_id;

    NEXT p_client_job_id IN p_send_parameters;
    p_client_job_id^ := client_job_id;
    send_parameters_size := #SIZE (client_job_id);
  PROCEND build_job_begin_vars;
?? TITLE := 'create_client_job_environment ', EJECT ??

  PROCEDURE create_client_job_environment
    (    user_id: ost$user_identification;
         account_name: avt$account_name;
         project_name: avt$project_name;
         system_supplied_job_name: jmt$system_supplied_name;
         user_supplied_job_name: jmt$user_supplied_name;
         job_mode: jmt$job_mode;
         family_access_kind: dft$family_access_kinds;
         job_lifetime: dft$lifetime;
     VAR client_job_list_entry: dft$client_job_list_entry;
     VAR mainframe_heap: ost$heap);

    VAR
      status: ost$status,
      p_client_job_space: ^dft$client_job_space;

    client_job_list_entry.system_supplied_job_name := system_supplied_job_name;
    client_job_list_entry.user_supplied_job_name := user_supplied_job_name;
    client_job_list_entry.job_mode := job_mode;
    client_job_list_entry.job_lifetime := job_lifetime;
    client_job_list_entry.inhibit_job_recovery := 0;
    client_job_list_entry.recovering := FALSE;
    ALLOCATE p_client_job_space IN mainframe_heap;
    IF p_client_job_space = NIL THEN
      osp$system_error (' NIL client_job_list_entry.p_client_job_space ', NIL);
    IFEND;

    p_client_job_space^.family := user_id.family;
    p_client_job_space^.user := user_id.user;
    p_client_job_space^.account := account_name;
    p_client_job_space^.project := project_name;
    p_client_job_space^.family_access_kind := family_access_kind;

{  p_client_job_space^.permanent_file_size_limit := UPPERVALUE (integer);

    osp$initialize_signature_lock (p_client_job_space^.queued_catalog_table_lock, status);
    p_client_job_space^.p_queued_catalog_table := NIL;
    p_client_job_space^.p_newest_queued_catalog := NIL;
    p_client_job_space^.p_attached_pf_table.table_p := NIL;
    p_client_job_space^.p_attached_pf_table.lowest_possible_free_entry := 0;

    initialize_job_heap (p_client_job_space^.p_job_heap, p_client_job_space^.job_heap);

    client_job_list_entry.request_count := 1;
    {  p_client_job_space^.active_clone_task_count := 0 {????????} ;
    client_job_list_entry.p_client_job_space := p_client_job_space;
  PROCEND create_client_job_environment;
?? TITLE := 'create_job_list ', EJECT ??

  PROCEDURE create_job_list
    (VAR mainframe_heap: {Input, Output} ost$heap;
     VAR client_job_list_pointer: dft$client_job_list_pointer);

    VAR
      job_index: dft$client_job_list_index;

    ALLOCATE client_job_list_pointer.p_client_job_list IN mainframe_heap;
    IF client_job_list_pointer.p_client_job_list = NIL THEN
      osp$system_error (' NIL p_client_job_list', NIL);
    IFEND;
    client_job_list_pointer.assignment := ' ';

  /initialize_jobs/
    FOR job_index := LOWERBOUND (client_job_list_pointer.p_client_job_list^)
          TO UPPERBOUND (client_job_list_pointer.p_client_job_list^) DO
      client_job_list_pointer.p_client_job_list^ [job_index].system_supplied_job_name := ' ';
      client_job_list_pointer.p_client_job_list^ [job_index].p_client_job_space := NIL;
    FOREND /initialize_jobs/;
  PROCEND create_job_list;
?? TITLE := 'delete_client_job_entry ', EJECT ??

  PROCEDURE delete_client_job_entry
    (    client_job_list_root: dft$client_job_list_root;
         client_job_id: dft$client_job_id;
     VAR mainframe_heap: {Input, Output} ost$heap);



    FREE client_job_list_root.p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          p_client_job_list^ [client_job_id.job_list_index].p_client_job_space IN mainframe_heap;
    client_job_list_root.p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          p_client_job_list^ [client_job_id.job_list_index].system_supplied_job_name := 'deleted';
    #SPOIL (client_job_list_root.p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].assignment);
    client_job_list_root.p_job_list_pointer_array^ [client_job_id.job_list_pointer_index].
          assignment (client_job_id.job_list_index) := dfc$free_entry_char;
  PROCEND delete_client_job_entry;

?? TITLE := 'get_free_client_job_table_entry', EJECT ??

  PROCEDURE get_free_client_job_table_entry
    (VAR client_job_list_root: {Input, Output} dft$client_job_list_root;
     VAR mainframe_heap: {Input, Output} ost$heap;
     VAR client_job_id: dft$client_job_id;
     VAR status: ost$status);

    VAR
      client_job_list_pointer: dft$client_job_list_pointer,
      free_entry_found: boolean,
      table_full: boolean;

    status.normal := TRUE;
    locate_free_job_entry (client_job_list_root, table_full, free_entry_found, client_job_id);
    IF table_full THEN
      osp$set_status_abnormal (dfc$file_server_id, dfe$maximum_jobs_connected, '', status);
      osp$append_status_integer (osc$status_parameter_delimiter,
            (dfc$client_job_list_size * UPPERBOUND (client_job_list_root.p_job_list_pointer_array^)), 10,
            FALSE, status);
    ELSEIF NOT free_entry_found THEN
      create_job_list (mainframe_heap, client_job_list_pointer);
      update_pointer_array (client_job_list_root, client_job_list_pointer,
            client_job_id.job_list_pointer_index);
      client_job_id.job_list_index := LOWERBOUND (client_job_list_pointer.p_client_job_list^);
    IFEND;

  PROCEND get_free_client_job_table_entry;
?? TITLE := 'initialize_job_heap ', EJECT ??

{
{ Must fake out the heap manager into formatting our short heap as a
{ ost$heap
{

  PROCEDURE initialize_job_heap
    (VAR p_job_heap: ^ost$heap;
     VAR job_heap: dft$job_heap);

    TYPE
      converter_type = record
        case (short, long) of
        = short =
          short_heap: ^dft$job_heap,
        = long =
          long_heap: ^ost$heap,
        casend,
      recend;

    VAR
      converter: converter_type;

    converter.short_heap := ^job_heap;
    p_job_heap := converter.long_heap;
    osp$reset_heap (p_job_heap, #SIZE (dft$job_heap), TRUE, 2);

  PROCEND initialize_job_heap;

?? TITLE := 'locate_client_job ', EJECT ??

  PROCEDURE locate_client_job
    (    system_supplied_job_name: jmt$system_supplied_name;
         client_job_list_root: dft$client_job_list_root;
     VAR client_job_id: dft$client_job_id;
     VAR client_job_found: boolean);

    VAR
      job_list_index: dft$client_job_list_index,
      pointer_index: dft$job_list_ptr_array_index;

  /for_all_pointers/
    FOR pointer_index := 1 TO client_job_list_root.number_of_active_pointers DO

    /search_job_list/
      FOR job_list_index := 1 TO #SIZE (client_job_list_root.p_job_list_pointer_array^ [pointer_index].
            assignment) DO
        IF client_job_list_root.p_job_list_pointer_array^ [pointer_index].assignment (job_list_index) =
              dfc$assigned_entry_char THEN
          IF client_job_list_root.p_job_list_pointer_array^ [pointer_index].
                p_client_job_list^ [job_list_index].system_supplied_job_name = system_supplied_job_name THEN
            client_job_found := TRUE;
            client_job_id.job_list_pointer_index := pointer_index;
            client_job_id.job_list_index := job_list_index;
            RETURN;
          IFEND;
        IFEND;
      FOREND /search_job_list/;
    FOREND /for_all_pointers/;
    client_job_found := FALSE;
  PROCEND locate_client_job;
?? TITLE := 'locate_free_job_entry ', EJECT ??

  PROCEDURE locate_free_job_entry
    (    client_job_list_root: dft$client_job_list_root;
     VAR table_full: boolean;
     VAR free_entry_found: boolean;
     VAR client_job_id: dft$client_job_id);

    TYPE
      char_set = set of char;

    VAR
      found_character: integer,
      free_char_set: char_set,
      pointers_index: dft$job_list_ptr_array_index;

    free_char_set := $char_set [dfc$free_entry_char];

  /scan_all_job_lists/
    FOR pointers_index := 1 TO client_job_list_root.number_of_active_pointers DO
      #SCAN (free_char_set, client_job_list_root.p_job_list_pointer_array^ [pointers_index].assignment,
            found_character, free_entry_found);
      IF free_entry_found THEN
        table_full := FALSE;
        client_job_id.job_list_pointer_index := pointers_index;
        client_job_id.job_list_index := found_character;
        RETURN;
      IFEND;
    FOREND /scan_all_job_lists/;

    free_entry_found := FALSE;
    table_full := client_job_list_root.number_of_active_pointers =
          UPPERBOUND (client_job_list_root.p_job_list_pointer_array^);
  PROCEND locate_free_job_entry;

?? TITLE := 'remove_client_job ', EJECT ??

{
{   The purpose of this request is to remove the client job environment
{ from the server.  All permanent files left attached are detached.
{ All tables on the server associated with the client job are deleted.
{

  PROCEDURE remove_client_job
    (    p_client_mainframe_file: dft$p_mainframe_file;
         client_job_id: dft$client_job_id;
     VAR status: ost$status);

    VAR
      return_files_option: pft$return_files_option;

    status.normal := TRUE;
    osp$set_signature_lock (p_client_mainframe_file^.mainframe_header.client_job_list_lock, osc$wait, status);
    IF status.normal THEN
      return_files_option.return_files := TRUE;
      return_files_option.log_returned_files := TRUE;
      return_files_option.wait_for_down_volume := FALSE;
      pfp$process_job_end (p_client_mainframe_file^.mainframe_header.client_mainframe_id,
            return_files_option);

      delete_client_job_entry (p_client_mainframe_file^.mainframe_header.client_job_list_root,
            client_job_id, p_client_mainframe_file^.mainframe_heap);
      osp$clear_signature_lock (p_client_mainframe_file^.mainframe_header.client_job_list_lock, status);
    IFEND;
  PROCEND remove_client_job;
?? TITLE := 'update_pointer_array ', EJECT ??

  PROCEDURE update_pointer_array
    (VAR job_list_table_root: {Input, Output} dft$client_job_list_root;
         client_job_list_pointer: dft$client_job_list_pointer;
     VAR assigned_pointers_index: dft$job_list_ptr_array_index);

    VAR
      actual: integer;

    job_list_table_root.p_job_list_pointer_array^ [job_list_table_root.number_of_active_pointers + 1] :=
          client_job_list_pointer;
    osp$increment_locked_variable (job_list_table_root.number_of_active_pointers,
          job_list_table_root.number_of_active_pointers, actual);
    assigned_pointers_index := job_list_table_root.number_of_active_pointers;
  PROCEND update_pointer_array;


MODEND dfm$client_job_manager;

