?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE Operator Facility : Operator Message Management' ??
MODULE ofm$job_message_processing;

{     This module is placed on the following libraries
{        OSF$SYSTEM_CORE_113

?? NEWTITLE := 'Global Declarations Referenced by This Module', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc jmt$system_supplied_name
*copyc jmt$user_supplied_name
*copyc ofc$base_error
*copyc ofc$max_messages_per_job
*copyc ofc$signal_contents
*copyc ofd$error_title
*copyc ofd$type_definition
*copyc ofe$error_codes
*copyc oft$operator_classes
*copyc oft$operator_message_descriptor
*copyc oft$display_message_info
*copyc osc$status_parameter_delimiter
*copyc tmc$signal_identifiers
?? POP ??
*copyc jmp$get_ijle_p
*copyc jmp$get_job_internal_info
*copyc osp$clear_mainframe_sig_lock
*copyc osp$reset_heap
*copyc osp$set_mainframe_sig_lock
*copyc osp$set_status_abnormal
*copyc osp$system_error
*copyc pmp$get_executing_task_gtid
*copyc pmp$get_job_names
*copyc pmp$ready_task
*copyc pmp$send_signal
*copyc dpv$enable_stop_key
*copyc oss$job_fixed
*copyc oss$mainframe_pageable
*copyc jmv$ijl_p
*copyc jmv$jcb
*copyc jmv$kjlx_p
*copyc osv$mainframe_pageable_heap
*copyc osv$task_private_heap
?? OLDTITLE ??
?? NEWTITLE := 'Global Declarations Declared by This Module', EJECT ??

  VAR
    ofv$message_queue_head_p: [STATIC, oss$mainframe_pageable] ^oft$operator_message_descriptor := NIL,
    ofv$message_queue_lock: [STATIC, oss$mainframe_pageable] ost$signature_lock := [0],
    ofv$message_structure_heap_p: [STATIC, oss$mainframe_pageable] ^HEAP
          (REP ofc$maximum_queue_messages of oft$operator_message_descriptor) := NIL;


{ It is important that the operator class names in the following array are arranged
{ in ascending order according to their corresponding numeric definitions in the
{ oft$operator_class type definition.

  VAR
    operator_class_names: [READ] array [0 .. ofc$max_valid_operator_class] of string (osc$max_name_size) :=
          ['Removable Media Operator', 'System Operator'];

?? TITLE := 'ofp$acknowledge_operator_msg_r1', EJECT ??
*copyc ofh$acknowledge_operator_msg_r1

  PROCEDURE [XDCL, #GATE] ofp$acknowledge_operator_msg_r1
    (    message_id: oft$operator_message_id;
         active_operator_classes: oft$operator_classes;
         response: ost$string;
     VAR status: ost$status);

    VAR
      message_id_string: string (osc$max_string_size),
      message_id_string_length: integer,
      message_descriptor_p: ^oft$operator_message_descriptor,
      previous_descriptor_p: ^oft$operator_message_descriptor;

    status.normal := TRUE;
    STRINGREP (message_id_string, message_id_string_length, message_id);
    IF ofv$message_queue_head_p = NIL THEN
      osp$set_status_abnormal (ofc$operator_facility_id, ofe$invalid_message_id,
            message_id_string (1, message_id_string_length), status);
      RETURN;
    IFEND;

    osp$set_mainframe_sig_lock (ofv$message_queue_lock);
    message_descriptor_p := ofv$message_queue_head_p;
    previous_descriptor_p := NIL;

  /search_for_message/
    WHILE message_descriptor_p <> NIL DO
      IF (message_descriptor_p^.message_id = message_id) AND
            (message_descriptor_p^.message_class IN active_operator_classes) THEN
        IF message_descriptor_p^.acknowledgement_allowed THEN
          message_descriptor_p^.response_received := TRUE;
          message_descriptor_p^.response_message := response;
          IF message_descriptor_p^.clear_message_when_acknowledged THEN
            IF previous_descriptor_p = NIL THEN
              ofv$message_queue_head_p := message_descriptor_p^.next_descriptor_p;
            ELSE
              previous_descriptor_p^.next_descriptor_p := message_descriptor_p^.next_descriptor_p;
            IFEND;
          IFEND;
        ELSE
          osp$set_status_abnormal (ofc$operator_facility_id, ofe$acknowledgement_not_allowed,
                message_id_string (1, message_id_string_length), status);
        IFEND;
        EXIT /search_for_message/;
      IFEND;
      previous_descriptor_p := message_descriptor_p;
      message_descriptor_p := message_descriptor_p^.next_descriptor_p;
    WHILEND /search_for_message/;

    osp$clear_mainframe_sig_lock (ofv$message_queue_lock);

    IF message_descriptor_p = NIL THEN
      osp$set_status_abnormal (ofc$operator_facility_id, ofe$invalid_message_id,
            message_id_string (1, message_id_string_length), status);
    ELSEIF message_descriptor_p^.clear_message_when_acknowledged THEN
      FREE message_descriptor_p IN ofv$message_structure_heap_p^;
    ELSEIF status.normal THEN {Need to ready task so it can receive the message
      pmp$ready_task (message_descriptor_p^.sending_task, status);
    IFEND;

  PROCEND ofp$acknowledge_operator_msg_r1;
?? TITLE := 'ofp$clear_operator_message_r1', EJECT ??
*copyc ofh$clear_operator_message_r1

  PROCEDURE [XDCL, #GATE] ofp$clear_operator_message_r1
    (    operator_class: oft$operator_class;
     VAR status: ost$status);

    VAR
      gtid: ost$global_task_id,
      message_descriptor_p: ^oft$operator_message_descriptor,
      previous_descriptor_p: ^oft$operator_message_descriptor;

    status.normal := TRUE;
    IF ofv$message_queue_head_p = NIL THEN
      osp$set_status_abnormal (ofc$operator_facility_id, ofe$no_message_outstanding,
            operator_class_names [operator_class], status);
      RETURN;
    IFEND;

    pmp$get_executing_task_gtid (gtid);
    osp$set_mainframe_sig_lock (ofv$message_queue_lock);
    message_descriptor_p := ofv$message_queue_head_p;
    previous_descriptor_p := NIL;

  /search_for_message/
    WHILE message_descriptor_p <> NIL DO
      IF (message_descriptor_p^.sending_task = gtid) AND (message_descriptor_p^.message_class =
            operator_class) THEN
        IF previous_descriptor_p <> NIL THEN
          previous_descriptor_p^.next_descriptor_p := message_descriptor_p^.next_descriptor_p;
        ELSE
          ofv$message_queue_head_p := message_descriptor_p^.next_descriptor_p;
        IFEND;
        EXIT /search_for_message/;
      IFEND;
      previous_descriptor_p := message_descriptor_p;
      message_descriptor_p := message_descriptor_p^.next_descriptor_p;
    WHILEND /search_for_message/;

    osp$clear_mainframe_sig_lock (ofv$message_queue_lock);

    IF message_descriptor_p <> NIL THEN
      FREE message_descriptor_p IN ofv$message_structure_heap_p^;
    ELSE
      osp$set_status_abnormal (ofc$operator_facility_id, ofe$no_message_outstanding,
            operator_class_names [operator_class], status);
    IFEND;

  PROCEND ofp$clear_operator_message_r1;
?? TITLE := 'ofp$get_operator_messages', EJECT ??
*copyc ofh$get_operator_messages

  PROCEDURE [XDCL, #GATE] ofp$get_operator_messages
    (    active_operator_classes: oft$operator_classes;
     VAR message_array: array [1 .. * ] of oft$operator_message_descriptor;
     VAR count: integer;
     VAR status: ost$status);

    VAR
      messages_with_responses: 0 .. ofc$maximum_queue_messages,
      message_descriptor_p: ^oft$operator_message_descriptor;

    status.normal := TRUE;
    count := 0;
    messages_with_responses := 0;
    IF ofv$message_queue_head_p = NIL THEN
      RETURN;
    IFEND;

    osp$set_mainframe_sig_lock (ofv$message_queue_lock);
    message_descriptor_p := ofv$message_queue_head_p;

  /search_for_message/
    WHILE message_descriptor_p <> NIL DO
      IF (message_descriptor_p^.message_class IN active_operator_classes) THEN
        count := count + 1;
        IF count > ofc$maximum_queue_messages THEN
          osp$system_error ('OF message queue error', NIL);
          RETURN;
        IFEND;

        IF message_descriptor_p^.response_received THEN

{ If the message has received a response, then do not return it to the caller.

          messages_with_responses := messages_with_responses + 1;
        ELSE
          IF (count - messages_with_responses) <= UPPERBOUND (message_array) THEN
            message_array [count - messages_with_responses] := message_descriptor_p^;
          IFEND;
        IFEND;
      IFEND;

      message_descriptor_p := message_descriptor_p^.next_descriptor_p;
    WHILEND /search_for_message/;

    osp$clear_mainframe_sig_lock (ofv$message_queue_lock);

{ Return to the caller only the count of active messages.

    count := count - messages_with_responses;

  PROCEND ofp$get_operator_messages;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] ofp$job_begin', EJECT ??
*copyc ofh$job_begin

  PROCEDURE [XDCL, #GATE] ofp$job_begin;

    VAR
      hp_p: ^ost$heap;

    IF ofv$message_structure_heap_p = NIL THEN
      ALLOCATE ofv$message_structure_heap_p IN osv$mainframe_pageable_heap^;
      hp_p := #LOC (ofv$message_structure_heap_p^);
      osp$reset_heap (hp_p, #SIZE (ofv$message_structure_heap_p^), TRUE, 2);
    IFEND;
  PROCEND ofp$job_begin;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] ofp$job_end', EJECT ??
*copyc ofh$job_end

  PROCEDURE [XDCL, #GATE] ofp$job_end;

    VAR
      job_name: jmt$user_supplied_name,
      job_sequence: jmt$system_supplied_name,
      message_descriptor_p: ^oft$operator_message_descriptor,
      previous_descriptor_p: ^oft$operator_message_descriptor,
      status: ost$status;

    status.normal := TRUE;

    pmp$get_job_names (job_name, job_sequence, status);

    IF ofv$message_queue_head_p = NIL THEN
      RETURN;
    IFEND;

    osp$set_mainframe_sig_lock (ofv$message_queue_lock);
    message_descriptor_p := ofv$message_queue_head_p;
    previous_descriptor_p := NIL;

    WHILE message_descriptor_p <> NIL DO
      IF message_descriptor_p^.system_supplied_name = job_sequence THEN
        IF previous_descriptor_p <> NIL THEN
          previous_descriptor_p^.next_descriptor_p := message_descriptor_p^.next_descriptor_p;
        ELSE
          ofv$message_queue_head_p := message_descriptor_p^.next_descriptor_p;
        IFEND;
        FREE message_descriptor_p IN ofv$message_structure_heap_p^;
        IF previous_descriptor_p <> NIL THEN
          message_descriptor_p := previous_descriptor_p^.next_descriptor_p;
        ELSE
          message_descriptor_p := ofv$message_queue_head_p;
        IFEND;
      ELSE
        previous_descriptor_p := message_descriptor_p;
        message_descriptor_p := message_descriptor_p^.next_descriptor_p;
      IFEND;
    WHILEND;

    osp$clear_mainframe_sig_lock (ofv$message_queue_lock);

    jmv$jcb.ijle_p^.display_message.display_message.size := 0;
    jmv$jcb.ijle_p^.display_message.display_message_lock.lock_id := 0;

  PROCEND ofp$job_end;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, UNSAFE] ofp$job_operator_msgs_active', EJECT ??
*copyc ofh$job_operator_msgs_active

  FUNCTION [XDCL, UNSAFE] ofp$job_operator_msgs_active
    (    job_name: jmt$system_supplied_name): boolean;

    VAR
      message_descriptor_p: ^oft$operator_message_descriptor;

    ofp$job_operator_msgs_active := FALSE;
    IF ofv$message_queue_head_p = NIL THEN
      RETURN;
    IFEND;

    osp$set_mainframe_sig_lock (ofv$message_queue_lock);
    message_descriptor_p := ofv$message_queue_head_p;

  /search_for_message/
    WHILE message_descriptor_p <> NIL DO
      IF ((message_descriptor_p^.system_supplied_name = job_name) AND
            NOT message_descriptor_p^.response_received) THEN
        ofp$job_operator_msgs_active := TRUE;
        EXIT /search_for_message/;
      IFEND;

      message_descriptor_p := message_descriptor_p^.next_descriptor_p;
    WHILEND /search_for_message/;

    osp$clear_mainframe_sig_lock (ofv$message_queue_lock);

  FUNCEND ofp$job_operator_msgs_active;
?? TITLE := 'ofp$receive_operator_resp_r1', EJECT ??

*copyc ofh$receive_operator_resp_r1

  PROCEDURE [XDCL, #GATE] ofp$receive_operator_resp_r1
    (    operator_class: oft$operator_class;
     VAR response: ost$string;
     VAR status: ost$status);

    VAR
      gtid: ost$global_task_id,
      message_descriptor_p: ^oft$operator_message_descriptor,
      previous_descriptor_p: ^oft$operator_message_descriptor;

    status.normal := TRUE;
    pmp$get_executing_task_gtid (gtid);
    IF ofv$message_queue_head_p = NIL THEN
      osp$set_status_abnormal (ofc$operator_facility_id, ofe$no_message_outstanding,
            operator_class_names [operator_class], status);
      RETURN;
    IFEND;

    osp$set_mainframe_sig_lock (ofv$message_queue_lock);
    message_descriptor_p := ofv$message_queue_head_p;
    previous_descriptor_p := NIL;

  /search_for_message/
    WHILE message_descriptor_p <> NIL DO
      IF (message_descriptor_p^.message_class = operator_class) AND
            (message_descriptor_p^.sending_task = gtid) THEN
        IF message_descriptor_p^.response_received THEN
          response := message_descriptor_p^.response_message;
          IF previous_descriptor_p = NIL THEN
            ofv$message_queue_head_p := message_descriptor_p^.next_descriptor_p;
          ELSE
            previous_descriptor_p^.next_descriptor_p := message_descriptor_p^.next_descriptor_p;
          IFEND;
        ELSE
          osp$set_status_abnormal (ofc$operator_facility_id, ofe$no_response_available,
                operator_class_names [operator_class], status);
        IFEND;

        EXIT /search_for_message/;
      IFEND;

      previous_descriptor_p := message_descriptor_p;
      message_descriptor_p := message_descriptor_p^.next_descriptor_p;
    WHILEND /search_for_message/;

    osp$clear_mainframe_sig_lock (ofv$message_queue_lock);

    IF message_descriptor_p <> NIL THEN
      IF status.normal THEN
        FREE message_descriptor_p IN ofv$message_structure_heap_p^;
      IFEND;
    ELSE
      osp$set_status_abnormal (ofc$operator_facility_id, ofe$no_message_outstanding,
            operator_class_names [operator_class], status);
    IFEND;

  PROCEND ofp$receive_operator_resp_r1;
?? TITLE := 'ofp$send_operator_message_r1', EJECT ??

*copyc ofh$send_operator_message_r1

  PROCEDURE [XDCL, #GATE] ofp$send_operator_message_r1
    (    formatted_message: oft$formatted_operator_message;
         number_of_message_lines: oft$number_of_displayable_lines;
         operator_class: oft$operator_class;
         acknowledgement_allowed: boolean;
         clear_message_when_acknowledged: boolean;
     VAR status: ost$status);

    VAR
      gtid: ost$global_task_id,
      job_message_counter: 0 .. ofc$max_messages_per_job + 1,
      last_descriptor_p: ^oft$operator_message_descriptor,
      max_messages_string: string (osc$max_string_size),
      max_messages_string_length: integer,
      message_descriptor_p: ^oft$operator_message_descriptor,
      message_id: 0 .. ofc$max_message_ordinal,
      new_message_p: ^oft$operator_message_descriptor,
      next_message_id: [STATIC, oss$mainframe_pageable] 0 .. ofc$max_message_ordinal := 0,
      ssn: jmt$system_supplied_name,
      usn: jmt$user_supplied_name;

    status.normal := TRUE;
    pmp$get_executing_task_gtid (gtid);
    pmp$get_job_names (usn, ssn, status);
    ALLOCATE new_message_p IN ofv$message_structure_heap_p^;
    IF new_message_p = NIL THEN
      osp$set_status_abnormal (ofc$operator_facility_id, ofe$allocate_structure_failed, ' ', status);
      RETURN;
    IFEND;

    osp$set_mainframe_sig_lock (ofv$message_queue_lock);
    message_id := next_message_id;

  /queue_message/
    BEGIN

    /validate_message/
      WHILE TRUE DO
        job_message_counter := 0;
        last_descriptor_p := NIL;
        message_descriptor_p := ofv$message_queue_head_p;
        message_id := (message_id + 1) MOD ofc$max_message_ordinal;
        WHILE message_descriptor_p <> NIL DO
          IF message_descriptor_p^.message_id <> message_id THEN
            IF message_descriptor_p^.system_supplied_name = ssn THEN
              job_message_counter := job_message_counter + 1;
              IF job_message_counter > ofc$max_messages_per_job THEN
                STRINGREP (max_messages_string, max_messages_string_length, ofc$max_messages_per_job);
                osp$set_status_abnormal (ofc$operator_facility_id, ofe$max_job_operator_messages,
                      max_messages_string (1, max_messages_string_length), status);
                FREE new_message_p IN ofv$message_structure_heap_p^;
                EXIT /queue_message/;
              IFEND;
              IF (message_descriptor_p^.sending_task = gtid) AND
                    (message_descriptor_p^.message_class = operator_class) THEN
                osp$set_status_abnormal (ofc$operator_facility_id, ofe$message_outstanding,
                      operator_class_names [operator_class], status);
                FREE new_message_p IN ofv$message_structure_heap_p^;
                EXIT /queue_message/;
              IFEND;
            IFEND;
          ELSE
            CYCLE /validate_message/; {The message identifier is not unique.}
          IFEND;

          last_descriptor_p := message_descriptor_p;
          message_descriptor_p := message_descriptor_p^.next_descriptor_p;
        WHILEND;
        EXIT /validate_message/;
      WHILEND /validate_message/;

      IF last_descriptor_p = NIL THEN
        ofv$message_queue_head_p := new_message_p;
      ELSE
        last_descriptor_p^.next_descriptor_p := new_message_p;
      IFEND;

      next_message_id := message_id;
      new_message_p^.next_descriptor_p := NIL;
      new_message_p^.sending_task := gtid;
      new_message_p^.message_class := operator_class;
      new_message_p^.message_id := next_message_id;
      new_message_p^.acknowledgement_allowed := acknowledgement_allowed;
      new_message_p^.clear_message_when_acknowledged := clear_message_when_acknowledged;
      new_message_p^.system_supplied_name := ssn;
      new_message_p^.formatted_message := formatted_message;
      new_message_p^.number_of_message_lines := number_of_message_lines;
      new_message_p^.response_received := FALSE;
    END /queue_message/;

    osp$clear_mainframe_sig_lock (ofv$message_queue_lock);

  PROCEND ofp$send_operator_message_r1;
?? TITLE := 'ofp$task_end_helper ', EJECT ??

  PROCEDURE [XDCL, #GATE] ofp$task_end_helper;

    VAR
      gtid: ost$global_task_id,
      message_descriptor_p: ^oft$operator_message_descriptor,
      previous_descriptor_p: ^oft$operator_message_descriptor,
      status: ost$status;

    pmp$get_executing_task_gtid (gtid);
    IF ofv$message_queue_head_p = NIL THEN
      RETURN;
    IFEND;

    osp$set_mainframe_sig_lock (ofv$message_queue_lock);
    message_descriptor_p := ofv$message_queue_head_p;
    previous_descriptor_p := NIL;

    WHILE message_descriptor_p <> NIL DO
      IF message_descriptor_p^.sending_task = gtid THEN
        IF previous_descriptor_p <> NIL THEN
          previous_descriptor_p^.next_descriptor_p := message_descriptor_p^.next_descriptor_p;
        ELSE
          ofv$message_queue_head_p := message_descriptor_p^.next_descriptor_p;
        IFEND;
        FREE message_descriptor_p IN ofv$message_structure_heap_p^;
        IF previous_descriptor_p <> NIL THEN
          message_descriptor_p := previous_descriptor_p^.next_descriptor_p;
        ELSE
          message_descriptor_p := ofv$message_queue_head_p;
        IFEND;
      ELSE
        previous_descriptor_p := message_descriptor_p;
        message_descriptor_p := message_descriptor_p^.next_descriptor_p;
      IFEND;
    WHILEND;

    osp$clear_mainframe_sig_lock (ofv$message_queue_lock);

  PROCEND ofp$task_end_helper;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] ofp$display_status_msg_helper', EJECT ??

  PROCEDURE [XDCL, #GATE] ofp$display_status_msg_helper
    (    text: string ( * );
     VAR status: ost$status);

    VAR
      message_size: integer,
      message_size_string: string (osc$max_string_size),
      message_size_string_length: integer;

    status.normal := TRUE;

    message_size := #SIZE (text);
    IF message_size > ofc$max_display_message THEN
      message_size := ofc$max_display_message;
    IFEND;

    osp$set_mainframe_sig_lock (jmv$jcb.ijle_p^.display_message.display_message_lock);
    jmv$jcb.ijle_p^.display_message.display_message.size := message_size;
    jmv$jcb.ijle_p^.display_message.display_message.text := text (1, message_size);
    osp$clear_mainframe_sig_lock (jmv$jcb.ijle_p^.display_message.display_message_lock);

    IF #SIZE (text) > message_size THEN
      STRINGREP (message_size_string, message_size_string_length, ofc$max_display_message);
      osp$set_status_abnormal (ofc$operator_facility_id, ofe$message_too_long,
            message_size_string (1, message_size_string_length), status);
    IFEND;

  PROCEND ofp$display_status_msg_helper;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] ofp$get_display_message_helper', EJECT ??

  PROCEDURE [XDCL, #GATE] ofp$get_display_message_helper
    (    job_seq_number: jmt$system_supplied_name;
     VAR display_message: oft$display_message;
     VAR status: ost$status);

    VAR
      ijle_p: ^jmt$initiated_job_list_entry,
      internal_info: jmt$job_internal_information;

    status.normal := TRUE;
    jmp$get_job_internal_info (job_seq_number, internal_info, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    jmp$get_ijle_p (internal_info.ijl_ordinal, ijle_p);
    display_message := ijle_p^.display_message.display_message;
  PROCEND ofp$get_display_message_helper;
?? OLDTITLE ??
?? NEWTITLE := '[XDCL, #GATE] ofp$enable_stop_key_help', EJECT ??

  PROCEDURE [XDCL, #GATE] ofp$enable_stop_key_help;

    dpv$enable_stop_key := TRUE;

  PROCEND ofp$enable_stop_key_help;

MODEND ofm$job_message_processing;
