#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2000,2019 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# sccsid = "@(#)72   1.19.1.16   src/rsct/rm/ER/cli/bin/chresponse.perl, errmcli, rsct_rady, rady2035a 11/12/15 16:39:03"
######################################################################
#                                                                    #
# Module: chresponse                                                 #
#                                                                    #
# Purpose:                                                           #
#   chresponse - add or delete actions of a response                 #
#                                                                    #
# Syntax:                                                            #
#   chresponse [-h] -a -n ActionName [-d DaysOfWeek ...]             #
#              [-t TimeOfDay ...] -s ActionScript [-r ReturnCode]    #
#              [-E Env_var=Value[,Env_var=Value,...]] [-u] [-b]      #
#              [-e a|r|b|e|A] [-o] [-TV] Response[:Node_name]        #
#   chresponse [-h] -p -n ActionName [-TV] Response[:Node_name]      #
#   chresponse [-h] -c NewResponse [-TV] Response[:Node_name]        #
#   chresponse [-h] -U|-L [-TV] Response[:Node_name]                 #
# Flags:                                                             #
#   -h      help - writes this command's usage statement to stdout   #
#   -a      Add an action to the response.                           #
#   -b      Specifies that the action being added to the response    #
#           supports event batching. The response must support event #
#           batching to use this flag. The -b flag cannot be         #
#           specified with the -e flag.                              #
#   -p      Delete an action from the response.                      #
#   -c      NewResponse. Rename the Response to this name.           #
#   -n      ActionName.  The name of the action to be added or       #
#           deleted.                                                 #
#   -d      DaysOfWeek.  The days the added action is allowed to be  #
#           used. 1=Sunday, 2=Monday, etc.  Use +'s between dates    #
#           and -'s for ranges (ex:1+7 or 2-6).  More than one       #
#           DaysOfWeek can be specified and is separated by (,)      #
#           comma.  Number of DaysOfWeek must match number of        #
#           TimeOfDay. Default is everyday (1-7).                    #
#   -t      TimeOfDay.  The time the added action is allowed to be   #
#           used for the corresponding DaysOfWeek. It is specified   #
#           in 24 hour format as HHMM (ex:1700 for 5pm). More than   #
#           one TimeOfDay can be specified and is separated by (,)   #
#           comma.  Number of DaysOfWeek must match number of        #
#           TimeOfDay. Default is all day (0000-2400).               # 
#   -s      ActionScript.  Fully qualified path for the script or    #
#           command that is executed for the added action.           #
#   -r      ReturnCode.  The expected return code for ActionScript.  #
#           The default is 0. If specified, the actual return code   #
#           is compared to the expected return code and a message is #
#           written to the Audit Log on whether they match or not.   #
#           If not specified, the actual return code is written to   #
#           the Audit Log.                                           #
#   -e      a|r|b|e|A.  Determines if the action is for an arm event,#
#           a rearm event, or both, or for an error event, or for    #
#           any type of event. Default is a.                         #
#   -o      Specifying -o saves the standard out output of the       #
#           ActionScript to the Audit Log.  Default is not to save   # 
#           the standard out.                                        #
#   -E      Env_var=Value.  Specifies any environment variables to   #
#           be set prior to running the Action script.               #
#   -u      Specifies that the action is to be run when a monitored  #
#           resource becomes undefined.                              #
#   -L      Lock. Lock the condition definition so no more changes   #
#           can be made.                                             #
#   -U      Unlock. Unlock the condition definition so changes to    #
#           the definition can be made.                              #
#   -T      Trace. IBM Support Center use only.                      #
#   -V      Verbose.                                                 #
#                                                                    #
# Operands:                                                          #
#   Response       The name of the response to be modified. Node_name#
#                  specifies where the condition is defined.         #
#                                                                    #
# Description:                                                       #
#   The chresponse command adds an action to a response or deletes   #
#   an action from a response. Actions define commands to be run when#
#   the response is used with a condition and the condition occurs.  #
#   The chresponse command can also be used to rename a response.    #
#                                                                    #
# Exit Values:                                                       #
#   0  ERRM_CLI_SUCCESS      Command completed successfully.         #
#   1  ERRM_CLI_RMC_ERROR    Command terminated due to an underlying #
#                            RMC error.                              #
#   2  ERRM_CLI_ERROR        Command terminated due to an underlying #
#                            error in the command script.            #
#   3  ERRM_CLI_BAD_FLAG     Command terminated due to user          #
#                            specifying an invalid flag.             #
#   4  ERRM_CLI_BAD_OPERAND  Command terminated due to user          #
#                            specifying a bad operand.               #
#   5  ERRM_CLI_USER_ERROR   Command terminated due to a user error. #
#                            For example specifying a name that      #
#                            already exists.                         #
#                                                                    #
# Examples:                                                          #
#   1. Delete the action named "E-mail root" from the response named #
#      "E-mail root anytime" ("E-mail root" cannot be the only       #
#      action):                                                      #
#      chresponse -p -n "E-mail root"  "E-mail root anytime"         #
#   2. Add the action named "E-mail root" to the response named      #
#      "E-mail root anytime", to be used anytime Monday through      #
#      Friday from 8am to 6pm that uses the command                  #
#      "/opt/rsct/bin/notifyevent root", saves the standand     #
#      out, and expects a return code of 5:                          #
#      chresponse -a -n "E-mail root" -d 2-6 -t 0800-1600     \      #
#           -s "/opt/rsct/bin/notifyevent root" -o -r 5  \      #
#           "E-mail root anytime"                                    #
#   3. To rename the response "E-mail root anytime" to               #
#      "E-mail root and admin anytime" :                             #
#      chresponse -c "E-mail root and admin"  "E-mail root anytime"  #
#                                                                    #
# Man Page:                                                          #
#   For the most current detailed description of this command see    #
#   the chresponse man page in /opt/rsct/man.                   #
#                                                                    #
#--------------------------------------------------------------------#
# Inputs:                                                            #
#   /opt/rsct/msgmaps/errmcli.chresponse.map - message mapping  #
#                                                                    #
# Outputs:                                                           #
#   stdout - none.                                                   #
#   stderr - any error message.                                      #
#                                                                    #
# External Ref:                                                      #
#   Commands: ctdspmsg                                               #
#   Modules:  ERRM_cli_utils.pm, ERRM_cli_rc.pm                      #
#             CT_cli_utils.pm                                        #
#   Perl library routines: Getopt::Std                               #
#                                                                    #
# Tab Settings:                                                      #
#   4 and tabs should be expanded to spaces before saving this file. #
#   in vi:  (:set ts=4  and   :%!expand -4)                          #
#                                                                    #
# Change Activity:                                                   #
#   001103 JAC 67469: Initial design & write.                        #
#   010211 JAC 67471: completed chresponse command.                  #
#   010214 JAC 71203: Process default date and time properly.        #
#   010216 JAC 71474: Correct comparison of number of dates/times.   #
#   010308 JAC 71005: Escape some special characters in strings.     #
#   010507 JAC 73620: Check for RMC CLI user error (rc=5) and        #
#                     return ERRM user error for this case.          #
#   011120 JAC 77597: Distributed RMC. Check for locator.            #
#   011128 JAC 77599: Add processing for new EnvList in Actions.     #
#   011203 JAC 78058: Add processing for new UndefResFlag in Actions.#
#   011206 JAC 78841: Fix selection string for locating resources.   #
#   011213 JAC 78976: Fix selection string for locating resources.   #
#   020107 JAC 79091: get_source_node omitted from utils use stmt.   #
#   020121 JAC 79558: Fix selection string for locating resources.   #
#   020128 JAC 79559: Change how destination/locator node is used.   #
#   020208 JAC 72176: Add new message for -a,-p or -c required.      #
#   020212 JAC 77598: Allow Actions to be optional.                  #
#   020419 JAC 81754: Use xxx-api where possible.                    #
#   020719 JAC 84425: Add $rc to process_api_error call.             #
#   020729 JAC 85061: Use 4 (DM/SR/local) for scope if locator used  #
#                     and scope not set.                             #
#   030620 JAC 96060: Add -U|-L for Locked attribute.                #
#   040407 JAC 105863: Use escape_chars for "\" searches.            #
#   071026 JAC 146726: set delimiter for -api calls.                 #
#   071031 JAC 147387: fix typo for -I                               #
#   081031 JAC 153203: add error events.                             #
#   081112 JAC 153204: add event batching.                           #
#   081218 JAC 155134: don't require -b for -p.                      #
######################################################################

#--------------------------------------------------------------------#
# General Program Flow/Logic:                                        #
#                                                                    #
# 1. Parse command line flags and operands, determine which flavor   #
#    of this command we are actually invoking.                       #
#    This command allows a user to change and rename responses       #
# 2. Print usage if -h specified                                     #
# 3. Make sure one and only one response is specified and it exists  #
# 4. If -c is specified for rename, verify that the new name does    #
#    not exist. Use the RMC chrsrc command to change the response    #
# 5. Use the RMC lsrsrc command to get the response information.     #
#    Find all actions that belong to it.                             #
# 6. If -a is specified to add an action, format the new action      #
#    properly and add it to the end of the list of existing actions. #
# 7. If -p is specified to delete an action, find the action name in #
#    the list of actions.  Also make sure there is more than one     #
#    actions.  Response must have at least one action.               #
# 8. Use the RMC chrsrc command to update the response with the new  #
#    action or deleted action.                                       #
# 9 .Return back any errors.                                         #
#                                                                    #
#--------------------------------------------------------------------#

#--------------------------------------------------------------------#
# Included Libraries and Extensions                                  #
#--------------------------------------------------------------------#
use lib "/opt/rsct/pm";
use locale;
use Getopt::Long;

use CT_cli_utils qw(printIMsg
                    printEMsg);
use CT_cli_input_utils qw(escape_chars);

use ERRM_cli_rc qw(ERRM_CLI_SUCCESS ERRM_CLI_RMC_ERROR
                   ERRM_CLI_ERROR ERRM_CLI_BAD_FLAG
                   ERRM_CLI_BAD_OPERAND ERRM_CLI_USER_ERROR);
use ERRM_cli_utils qw(error_exit
                    printCIMsg
                    printCEMsg
                    parse_days_string parse_time_string
                    get_locator_node
                    get_source_node
                    set_orig_rmc_scope check_set_cluster_scope
                    process_api_error process_exit_code
                    find_resource_name get_handle
                    change_locked_attr
                    $CTDIR $CTBINDIR $LSNOTFND $GARBAGE
                    @EVENTTYPE @EVENTTPCD
                    $TRUE $FALSE
                    $EVENT_BATCHING_ON $EVENT_BATCHING_OFF
                    $DELIMITERI $DELIMITERO
                    $RMC_CLI_USER_ERROR $RMC_LOCAL_SCOPE
                    $LSRSRC $CHRSRC $RSCEVRS);


#--------------------------------------------------------------------#
# Global Variables                                                   #
#--------------------------------------------------------------------#
Getopt::Long::Configure ("bundling", "no_auto_abbrev",
                         "no_ignore_case", "require_order",
                         "prefix_pattern=(--|-)");

$Trace = $FALSE;                        # default - trace off
$Verbose = $FALSE;                      # default - verbose turned off

$Scope_orig_set = $FALSE;               # default - no CT_MANAGEMENT_SCOPE
$Scope_orig_value = 0;                  # default - scope value

$AddFlag = $FALSE;                      # add flag for -a
$DeleteFlag = $FALSE;                   # delete flag for -p
$RenameFlag = $FALSE;                   # default - no rename
$Opt_DaysOfWeek = $FALSE;               # default - no days
$Opt_TimeOfDay = $FALSE;                # default - no time
$Opt_ReturnCode = $FALSE;               # default - no return code
$Opt_RetCodeCheck = $FALSE;             # default - no ret code check
$Opt_EventType = $FALSE;                # default - no event type
$Opt_StdOut = $FALSE;                   # default - no std out
$Opt_EnvList = $FALSE;                  # default - no env vars
$Opt_UndefRes = $FALSE;                 # default - no undefres
$Opt_Lock = $FALSE;                     # default - no set lock
$Opt_Unlock = $FALSE;                   # default - no set unlock
$Opt_Batching = $FALSE;                 # default - no event batching

$PROGNAME = "chresponse";               # Program Name for messages
$MSGCAT = "errmcli.cat";                # msg catalogue for this cmd
$LSMSG = "$CTBINDIR/ctdspmsg";          # list / display message rtn.
$ENV{'MSGMAPPATH'} = "$CTDIR/msgmaps";  # msg maps used by $LSMSG

#--------------------------------------------------------------------#
# Variables                                                          #
#--------------------------------------------------------------------#
my $response = "";                      # Response to update
my $response_handle = "";               # Response handle
my $newresp_name = "";                  # new response name for -c
my $action_name = "";                   # action name to create for -n
my $days_of_week = "";                  # expression for -d
my $days_coded = "";                    # days to pass to RMC CLI
my $time_of_day = "";                   # expression for -t
my $st_time_coded = "";                 # start times for RMC CLI
my $end_time_coded = "";                # end times for RMC CLI
my $action_script = "";                 # action command from -s
my $env_vars = "";                      # environment vars from -E
my $return_code = 0;                    # return code for -r
my $ret_code_flag = 0;                  # default ret code check
my $undefres_flag = 0;                  # default undefres flag
my $event_type = "";                    # event type for -e
my $std_out = 0;                        # default - no std out
my $passopts = "";                      # options to pass to RMC
my $other_opts = "";                    # options to pass to RMC
my $node_select = "";                   # used for NodeNameList
my $event_part = $EVENTTPCD[0];         # event part of Actions
my $rc_part = "";                       # the rc part of Actions
my $stdout_part = 0;                    # the stdout part of Actions
my @RespAct = ();                       # holds lsrsrc result
my $line = "";                          # holds lsrsrc result
my $num_Actions = -1;                   # counts the number of actions
my $start_pos = 0;                      # finds Actions start
my $end_pos = 0;                        # finds Actions end
my $end1_pos = 0;                       # finds possible end
my $end2_pos = 0;                       # finds possible end
my $i = 0;                              # general loop counter
my $comma = "";                         # use comma or not
my $delAct = -1;                        # Action to delete
my $ndays_coded = 0;                    # number of day strings
my $ntimes_coded = 0;                   # number of time strings
my $locator = "";                       # where the response is
my @cmd_out = ();                       # for -api output
my $lock_val = 0;                       # Locked attr value
my $event_batching = $EVENT_BATCHING_OFF; # event batching value

#--------------------------------------------------------------------#
# Main Code                                                          #
#--------------------------------------------------------------------#
my $rc = 0;

# save original rmc management scope value, in case it's changed later
if (defined $ENV{CT_MANAGEMENT_SCOPE}) {
   $Scope_orig_set = $TRUE;
   $Scope_orig_value = $ENV{CT_MANAGEMENT_SCOPE};
}

# parse the command line, exit if there are errors
($rc, $response, $action_name, $days_of_week, $time_of_day,
      $action_script, $return_code, $event_type,
      $newresp_name, $locator, $env_vars) = &parse_cmd_line;
($rc == 0) || error_exit($rc);

# scan for special charactes in action_script, including $
$action_script = escape_chars($action_script);
$action_script =~ s/\$/\\\$/g;

if ($Verbose) { printIMsg("IMsgchresponseStart",$response); }

if ($Trace) { $passopts = $passopts." -T"; }

if ($Verbose) { $passopts = $passopts." -V"; }

# if only changing Locked attribute, do it and leave
if ($Opt_Lock || $Opt_Unlock) {

   # set lock value
   if ($Opt_Lock) { $lock_val = 1;}
   if ($Opt_Unlock) { $lock_val = 0;}

   # call function to change Locked attribute
   $rc = change_locked_attr($lock_val,$locator,$RSCEVRS,$response);

   if ($Verbose) { printIMsg("IMsgchresponseEnd",$response);}
   exit($rc);
}

# if renaming the response, get the response handle, then set a
# new name for the resource
if ($RenameFlag) {                      # -c was specified

   # set CT_MANAGEMENT_SCOPE to original setting, in case it was used
   set_orig_rmc_scope;

   # if the destination node was not specified, change the local definition.
   # Make sure rmc scope is set to local scope.
   if ($locator eq "") {
      $ENV{CT_MANAGEMENT_SCOPE} = $RMC_LOCAL_SCOPE;
   }
   # a locator was specified, use it for NodeNameList
   else {
      $node_select = " && NodeNameList |< {\\\"$locator\\\"}";

      # use DM/SR/Local scope if scope not set
      check_set_cluster_scope;
   }

   # rename response using chrsrc
   if ($Trace) { print STDERR "$PROGNAME: calling chrsrc-api\n";}
#  `$CTBINDIR/$CHRSRC $passopts -s "Name==\\\"$response\\\" $node_select" $RSCEVRS Name="$newresp_name"`;
   @cmd_out = `$CTBINDIR/chrsrc-api -I $DELIMITERI -D $DELIMITERO -s ${RSCEVRS}${DELIMITERI}"Name==\\\"$response\\\" $node_select"${DELIMITERI}Name${DELIMITERI}"$newresp_name" 2>&1`;

   $rc = $?;
   $rc = &process_exit_code($rc);
   if ($Trace) {
      print STDERR "chrsrc-api results:\n";
      print STDERR "@cmd_out";
      print STDERR "$PROGNAME: chrsrc-api returned $rc\n";
   }

   # show any errors if there was a bad rc except for not found
   if ($rc != 0) {
      process_api_error($DELIMITERO,$rc,@cmd_out);
   }  

   # return ERRM CLI user error if it's an RMC CLI user error    73620
   ($rc == $RMC_CLI_USER_ERROR) && ( error_exit(ERRM_CLI_USER_ERROR) );

   # if chrsrc command failed, print RMC error message and exit
   if ($rc != 0) {
      printCEMsg ("EMsgERRMcliUnExpectRMCrc",$rc);
      exit (ERRM_CLI_RMC_ERROR);
      }
   }                                    # end rename response

# else we're going to add or delete an action
else {

   # set CT_MANAGEMENT_SCOPE to original setting, in case it was used
   set_orig_rmc_scope;

   # if the destination node was not specified, change the local definition.
   # Make sure rmc scope is set to local scope.
   if ($locator eq "") {
      $ENV{CT_MANAGEMENT_SCOPE} = $RMC_LOCAL_SCOPE;
   }
   # a locator was specified, use it for NodeNameList
   else {
      $node_select = " && NodeNameList |< {\\\"$locator\\\"}";

      # use DM/SR/Local scope if scope not set
      check_set_cluster_scope;
   }

   # list the response to get the actions
   if ($Trace) { print STDERR "$PROGNAME: calling lsrsrc-api\n";}
#  @RespAct = `$CTBINDIR/$LSRSRC $passopts -l -s "Name==\\\"$response\\\" $node_select" $RSCEVRS Actions`;
   @RespAct = `$CTBINDIR/lsrsrc-api -I $DELIMITERI -D $DELIMITERO -s ${RSCEVRS}${DELIMITERI}"Name==\\\"$response\\\" $node_select"${DELIMITERI}${DELIMITERI}${DELIMITERI}Actions${DELIMITERI}EventBatching 2>&1`;

   $rc = $?;
   $rc = &process_exit_code($rc);
   if ($Trace) {
      print STDERR "lsrsrc-api results:\n";
      print STDERR "@RespAct";
      print STDERR "$PROGNAME: lsrsrc-api returned $rc\n";
   }

   # show any errors if there was a bad rc except for not found
   if ($rc != 0) {
      process_api_error($DELIMITERO,$rc,@RespAct);
   }

   # return ERRM CLI user error if it's an RMC CLI user error    73620
   ($rc == $RMC_CLI_USER_ERROR) && ( error_exit(ERRM_CLI_USER_ERROR) );

   # if lsrsrc command failed, print RMC error message and exit
   if ($rc != 0) {
      printCEMsg ("EMsgERRMcliUnExpectRMCrc",$rc);
      exit (ERRM_CLI_RMC_ERROR);
      }

   # Count the number of Actions. Start with -1 so 0 index is 1st one.
   $num_Actions = -1;

   # break up the actions in @RespAct into an array of actions in @Actions
   # and into the current EventBatching attribute value
#  foreach $line (@RespAct) {
   #$line = $RespAct[0];
   ($line, $event_batching) = split (/$DELIMITERO/, $RespAct[0]);

   # check that this response already supports event batching if -b was used
   if ($Opt_Batching) {
      if (($event_batching eq "") || ($event_batching == 0)) {
         printEMsg("EMsgchresponseBButNoBatching");
         exit(ERRM_CLI_USER_ERROR);
      }
   }
   else {  # !Opt_Batching
      if ( $AddFlag && ($event_batching == 1) ) {
         printEMsg("EMsgchresponseNoBButBatching");
         exit(ERRM_CLI_USER_ERROR);
      }
   }

      # look at the Action next
      # find if this has the Action list
#     if ($line =~ /Actions/) {
         
         $start_pos = index $line,"{["; # find beginning of 1st action
         
         # there's only actions present if "{[" is found
         if ($start_pos >= 0) {

            $start_pos++; 
     
            # find the end of an action
            while ($start_pos >= 0){ 
               $end1_pos = index $line,"],["; # one possible ending (more actions)
               $end2_pos = index $line,"]}";  # end of last one
               $end_pos = $end2_pos;          # take a guess that is the last one

               # check that there's no more actions (fix guess if needed)
               if (($end1_pos < $end2_pos) && ($end1_pos >=0)) { $end_pos = $end1_pos; }

               # watch out for null action that looks like {[]}
               if (($end_pos-$start_pos) >1) {

                  $num_Actions++;             # bump the count

                  # add this action to the @Actions array
                  $Actions[$num_Actions] = substr($line,$start_pos,$end_pos-$start_pos+1);

                  # escape some things so we can put them back
                  #$Actions[$num_Actions] =~ s/\["/\['"/g;
                  #$Actions[$num_Actions] =~ s/",/"',/g;
                  #$Actions[$num_Actions] =~ s/,"/,'"/g;

                  # Do some escaping on strings.  Do the escape character first
                  # for anything that's a string, escape any inner \
                  #$Actions[$num_Actions] =~ s/\\/\\\\/g;

                  # for anything that's a string, escape any inner double quotes
                  #$Actions[$num_Actions] =~ s/\"/\\\"/g;
                  $Actions[$num_Actions] = escape_chars($Actions[$num_Actions]);
                  }                     # end of not {[]} null action

               # process the rest of the line
               $line = substr($line,$end_pos+2);

               # find where the next action starts
               $start_pos = index $line,"[";
               }                        # end of while loop
            }                           # end of if actions are present
#        }                              # end of if line has the actions
#     }                                 # end of foreach

   # do processing for adding an action
   if ($AddFlag) {

      # check to see if -d and/or -t was specified.  Make sure that
      # if one or the other wasn't specified, the number of default
      # values set matches what was specified.   (71203)

      # check to see if -d was not specified
      if (!$Opt_DaysOfWeek) {

         # check to see if -t was specified
         if ($Opt_TimeOfDay) {

            # process the times specified
            ($ntimes_coded,$st_time_coded, $end_time_coded) = parse_time_string($time_of_day);

            # make enough default dates to match
            $days_of_week = "1-7";
            for ($i=2;$i<=$ntimes_coded;$i++){
                $days_of_week = $days_of_week.",1-7";
                }

            # process the default dates
            ($ndays_coded,$days_coded) = parse_days_string($days_of_week);
            }   # end of -t specified (but no -d)

         else {  # no -t (and no -d)
            # set the default for days and times
            $days_of_week = "1-7";
            $time_of_day = "0000-2400";

            # process the days and times
            ($ndays_coded,$days_coded) = parse_days_string($days_of_week);
            ($ntimes_coded,$st_time_coded, $end_time_coded) = parse_time_string($time_of_day);

            }    # end of no -t and no -d
      }    # end of no -d specified

      else  {  # -d specified

         # check to see if -t was specified
         if ($Opt_TimeOfDay) {

            # process the days and times
            ($ndays_coded,$days_coded) = parse_days_string($days_of_week);
            ($ntimes_coded,$st_time_coded, $end_time_coded) = parse_time_string($time_of_day);
            }   # end of -t specified (with -d)

         else {  # no -t (but -d)

            # process the dates specified
            ($ndays_coded,$days_coded) = parse_days_string($days_of_week);

            # make enough default times to match
            $time_of_day = "0000-2400";
            for ($i=2;$i<=$ndays_coded;$i++){
                $time_of_day = $time_of_day.",0000-2400";
                }

            # process the default times
            ($ntimes_coded,$st_time_coded, $end_time_coded) = parse_time_string($time_of_day);

            }    # end of no -t with -d
         }    # end of -d specified

      # check that the number of days match the number of times
      if ($ndays_coded != $ntimes_coded) {           # error if they don't match
         printEMsg("EMsgchresponseNumDaysTimesDiff");
         exit(ERRM_CLI_USER_ERROR);
         }

      # set up the event, if specified
      if ($Opt_EventType) { $event_part = $event_type; } # -e was specified         

      # set up the std out flag, if specified
      if ($Opt_StdOut) { $stdout_part = 1; } # -o was specified         

      # set up the return code and check flag
      if (!$Opt_ReturnCode) { $return_code = 0; }    # -r not specified
      if ($Opt_RetCodeCheck) { $ret_code_flag = 1; } # -r was specified 

      # scan for special characters in env_vars, 1st \ then "
      #$env_vars =~ s/\\/\\\\/g;
      #$env_vars =~ s/\"/\\\"/g;
      $env_vars = escape_chars($env_vars);

      if ($Opt_UndefRes) { $undefres_flag = 1; }         # -u was specified

      # add to the number of Actions counter
      $num_Actions++;

      # add the new action to the Action array
      $Actions[$num_Actions] = "[\\\"$action_name\\\",{$days_coded},{$st_time_coded},{$end_time_coded},$action_script,$event_part,$ret_code_flag,$return_code,$stdout_part,{$env_vars},$undefres_flag]";

      # later, when rebuilding Actions for ERRM, don't delete any from the array
      # $delAct keeps track of the index of the action to delete for -p 
      $delAct = -1;
      }                          # end of if $AddFlag

   # for delete, find the action to delete
   if ($DeleteFlag) {

      # check each action name to see if it should be deleted
      for ($i=0;($i<=$num_Actions) && ($delAct<0);$i++) {
         $pos = index $Actions[$i],$action_name;
         if ($pos >=0 ) { $delAct = $i;}   # $delAct is the one to delete
         }

      # check to see if action not found (check for this before 1 action check
      # so user is told action name is wrong
      if ($delAct<0)  {
         printEMsg("EMsgchresponseActionNotFound",$action_name,$response_name);
         exit(ERRM_CLI_USER_ERROR);
         }

      # if only 1 action, can not delete it
      #if ($num_Actions==0){
      #   printEMsg("EMsgchresponseRemoveForOneAction",$action_name,$response_name);
      #   exit(ERRM_CLI_USER_ERROR);
      #   }
      }                          # end of if $DeleteFlag

   # rebuild the Actions so the can be written back out
   $NewAction = "{";                    # starting the string...
   $comma = "";                         # changes if there's >1 action

   # add each action in to the new Action string
   for ($i=0;$i<=$num_Actions;$i++){
      if ($i != $delAct) {              # skip the one to delete
         $NewAction = $NewAction . $comma . $Actions[$i];
         $comma = ",";                  # for next time around
         }
      }

   # add the last bracket
   $NewAction = $NewAction . "}";

   # set CT_MANAGEMENT_SCOPE to original setting, in case it was used
   set_orig_rmc_scope;

   # if the destination node was not specified, change the local definition.
   # Make sure rmc scope is set to local scope.
   if ($locator eq "") {
      $ENV{CT_MANAGEMENT_SCOPE} = $RMC_LOCAL_SCOPE;
      $node_select = "";
   }
   # a locator was specified, use it for NodeNameList
   else {
      $node_select = " && NodeNameList |< {\\\"$locator\\\"}";

      # use DM/SR/Local scope if scope not set
      check_set_cluster_scope;
   }

   # call RMC chrsrc to put the changed Action back
   if ($Trace) { print STDERR "$PROGNAME: calling chrsrc-api\n";}
#  `$CTBINDIR/$CHRSRC $passopts -s "Name==\\\"$response\\\" $node_select" $RSCEVRS Actions="$NewAction"`;
   @cmd_out = `$CTBINDIR/chrsrc-api -I $DELIMITERI -D $DELIMITERO -s ${RSCEVRS}${DELIMITERI}"Name==\\\"$response\\\" $node_select"${DELIMITERI}Actions${DELIMITERI}"$NewAction" 2>&1`;

   $rc = $?;
   $rc = &process_exit_code($rc);
   if ($Trace) {
      print STDERR "chrsrc-api results:\n";
      print STDERR "@cmd_out";
      print STDERR "$PROGNAME: chrsrc-api returned $rc\n";
   }

   # show any errors if there was a bad rc except for not found
   if ($rc != 0) {
      process_api_error($DELIMITERO,$rc,@cmd_out);
   }

   # return ERRM CLI user error if it's an RMC CLI user error    73620
   ($rc == $RMC_CLI_USER_ERROR) && ( error_exit(ERRM_CLI_USER_ERROR) );

   # if chrsrc command failed, print RMC error message and exit
   if ($rc != 0) {
      printCEMsg ("EMsgERRMcliUnExpectRMCrc",$rc);
      exit (ERRM_CLI_RMC_ERROR);
      }

   }                                   # end else this is add or delete

if ($Verbose) { printIMsg("IMsgchresponseEnd",$response); }

exit($rc);

#--------------------------------------------------------------------#
# End Main Code                                                      #
#--------------------------------------------------------------------#


#--------------------------------------------------------------------#
# parse_cmd_line - Parse the command line for options and operands.  #
#   Set appropriate global variables as outlined below, make sure we #
#   have a valid combination of arguments / options.                 #
#                                                                    #
# Return:                                                            #
#   $rc   0                  Command line parsed fine, no problem.   #
#         ERRM_CLI_BAD_FLAG  Command line contained a bad flag.      #
#   $resource                Name of resource to be changed.         #
#                                                                    #
# Global Variables Modified:                                         #
#   $Verbose           output   True (-V) turn Verbose mode on.      #
#   $Trace             output   True (-T) turn Trace mode on.        #
#   $AddFlag           output   True (-a) add an action              #
#   $DeleteFlag        output   True (-p) delete an action           #
#   $RenameFlag        output   True (-c) rename response specified  #
#   $Opt_DaysOfWeek    output   True (-d) days specified             #
#   $Opt_TimeOfDay     output   True (-t) times specified            #
#   $Opt_ReturnCode    output   True (-r) return code specified      #
#   $Opt_RetCodeCheck  output   True (-r) return code specified      #
#   $Opt_EventType     output   True (-e) event type specified       #
#   $Opt_StdOut        output   True (-o) save std out specified     #
#   $Opt_EnvList       output   True (-E) environment vars defined   #
#   $Opt_UndefRes      output   True (-u) undefine resource specified#
#   $Opt_Lock          output   True (-U) lock specified             #
#   $Opt_Unlock        output   True (-U) unlock specified           #
#   $Opt_Batching      output   True (-b) event batching specified.  #
#--------------------------------------------------------------------#
sub parse_cmd_line 
{
my(@original_argv) = @ARGV;
my $reponse_name = "";                  # response to change
my $new_name = "";                      # -c new name for response
my $action_name = "";                   # -n action name
my $days_str = "";                      # -d days string
my $time_str = "";                      # -t time string
my $command = "";                       # -s action script 
my $envlist = "";                       # environment vars list
my $ret_code_val = "";                  # -r return code
my $event_type = "";                    # -e event type
my $event_code = "";                    # event type code
my %opts = ();
my $i = 0;
my $Code_Found = $FALSE;                # flag to find valid event types
my $temp_name = "";                     # temporary name with locator
my $locator = "";                       # where the response is
my $lock_flag = "";                     # for invalid flag message
my $lock_flag2 = "";                    # for invalid flag message
my $j = 0;
my $temp_event = "";
my %event_spec = ();                    # indicate the event types specified

# Process the command line...
if (!GetOptions(\%opts,
		'h' ,
		'a' ,
		'b' ,
		'p' ,
		'c=s' ,
		'n=s' ,
		'd=s' ,
		't=s' ,
		's=s' ,
		'r=s' ,
		'e=s' ,
		'E=s' ,
		'u' ,
		'o' ,
		'U' ,
		'L' ,
		'V' ,
		'T')) {# Gather options; 
                                        # if errors
    &print_usage;                       # display proper usage
    return ERRM_CLI_BAD_FLAG;           # return bad rc - bad flag 
   }

# process h flag
if (defined $opts{h}) {                 # -h, help request
    &print_usage;                       # print usage statement
    exit(0);                            # all done with good return!
   }

if (defined $opts{T}) {                 # -T turn trace on
   $Trace = $TRUE;
   }

if (defined $opts{V}) {                 # -V turn verbose mode on
   $Verbose = $TRUE;
   }

# Get the arguments...
# Operands:  resource (only one resource allowed)
if ($#ARGV == 0) {                      # index 0 is last one
    $response_name = shift @ARGV;       # user specified resources

    # extract the locator, if it exists
    ($temp_name, $locator) = get_locator_node($response_name);
    # put back response name without locator
    if ($locator ne "") {
       $response_name = $temp_name;
    }

    # make sure the response exists
    $rc = find_resource_name($response_name,$RSCEVRS,$locator);
    if ($rc != 0) {                     # response not found
       if ($rc != $RMC_CLI_USER_ERROR) {
           printEMsg("EMsgchresponseResponseNotFound","$response_name");
           }
       exit(ERRM_CLI_USER_ERROR);
       }
    }

else {            
    # no response or too many responses specified 
    printCEMsg("EMsgERRMcliInvalidNumberOfOperands");
    &print_usage;
    return ERRM_CLI_BAD_OPERAND;
    }

# check for lock/unlock flags
if ((defined $opts{L}) || (defined $opts{U})) { # -U,-L for unlock,lock

   # set global flag
   if ( defined $opts{L} ) {
      $Opt_Lock = $TRUE;
      $lock_flag = "L";
   }
   if ( defined $opts{U} ) {
      $Opt_Unlock = $TRUE;
      $lock_flag = "U";
   }

   # these flags are not allowed together or with the other flags (apcndtsreEuo)
   if ( $Opt_Lock && $Opt_Unlock ) {
      $lock_flag = "L";
      $lock_flag2 = "U";
   }

   if (defined $opts{a}) { $lock_flag2 = "a";}
   if (defined $opts{p}) { $lock_flag2 = "p";}
   if (defined $opts{c}) { $lock_flag2 = "c";}
   if (defined $opts{n}) { $lock_flag2 = "n";}
   if (defined $opts{d}) { $lock_flag2 = "d";}
   if (defined $opts{t}) { $lock_flag2 = "t";}
   if (defined $opts{s}) { $lock_flag2 = "s";}
   if (defined $opts{r}) { $lock_flag2 = "r";}
   if (defined $opts{e}) { $lock_flag2 = "e";}
   if (defined $opts{E}) { $lock_flag2 = "E";}
   if (defined $opts{u}) { $lock_flag2 = "u";}
   if (defined $opts{o}) { $lock_flag2 = "o";}

   if ( $lock_flag2 ne "" ) {
      printCEMsg("EMsgERRMcliImproperUsageCombination",$lock_flag,$lock_flag2);
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   return(0, $response_name, $action_name, $days_str, $time_str,
       $command, $ret_code_val, $event_code,
       $new_name, $locator, $envlist);  # success
}

# check to see if the -a flag is used to add an action
if (defined $opts{a}) {                 # -a set add flag
   $AddFlag = $TRUE;
   }

# check to see if the -p flag is used to delete an action
if (defined $opts{p}) {                 # -p set delete flag
   $DeleteFlag = $TRUE;
   if ($AddFlag) {                      # no -p with -a
      printCEMsg("EMsgERRMcliImproperUsageCombination","-a","-p");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   }

# check to see if the -c flag is used to rename a response
if (defined $opts{c}) {                 # -c set rename flag
   $RenameFlag = $TRUE;
   if ($AddFlag) {                      # no -c with -a
      printCEMsg("EMsgERRMcliImproperUsageCombination","-a","-c");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   if ($DeleteFlag) {                   # no -c with -p
      printCEMsg("EMsgERRMcliImproperUsageCombination","-p","-c");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   $new_name = $opts{c};                # get new name 
   if ($new_name eq ""){                # no name for -c
      printCEMsg("EMsgERRMcliMissingRequiredFlagOperand","-c");
      &print_usage;
      return ERRM_CLI_BAD_OPERAND;
      }

   # make sure the new name doesn't exists
   $rc = find_resource_name($new_name,$RSCEVRS,$locator);
   if ($rc == $RMC_CLI_USER_ERROR) {
       exit(ERRM_CLI_USER_ERROR);
       }
   if ($rc == 0) {                     # response is found
      printEMsg("EMsgchresponseResponseExists","$new_name");
      exit(ERRM_CLI_USER_ERROR);
      }
   }

# must use -a or -p or -c
if (!$AddFlag && !$DeleteFlag && !$RenameFlag) {
      printEMsg("EMsgchresponseReqFlagMissing");
      &print_usage;
      return ERRM_CLI_USER_ERROR;
      } 

if (defined $opts{n}) {                 # -n for action name   
   if ($RenameFlag) {                   # no -n with -c
      printCEMsg("EMsgERRMcliImproperUsageCombination","-n","-c");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   $action_name = $opts{n};             # get action name
   if ($action_name eq ""){             # no action name for -n
      printCEMsg("EMsgERRMcliMissingRequiredFlagOperand","-n");
      &print_usage;
      return ERRM_CLI_BAD_OPERAND;
      }
   }
else {
   # -n not specified and is required 
   if (!$RenameFlag) {                  # no -c, -n required
      printCEMsg("EMsgERRMcliMissingRequiredFlag","-n");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   }

if (defined $opts{s}) {                 # -s for command string
   if ($RenameFlag) {                   # no -s with -c
      printCEMsg("EMsgERRMcliImproperUsageCombination","-c","-s");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   if ($DeleteFlag) {                   # no -s with -p
      printCEMsg("EMsgERRMcliImproperUsageCombination","-p","-s");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   $command = $opts{s};                 # get action script
   if ($command eq ""){                 # no command for -s
      printCEMsg("EMsgERRMcliMissingRequiredFlagOperand","-s");
      &print_usage;
      return ERRM_CLI_BAD_OPERAND;
      }
   }
else {
   # -s not specified and is required
   if ($AddFlag) {                      # -s required with -a
       printCEMsg("EMsgERRMcliMissingRequiredFlag","-s");
       &print_usage;
       return ERRM_CLI_BAD_FLAG;
       }
   }

if (defined $opts{d}) {                 # -d for days
   if ($RenameFlag) {                   # no -d with -c
      printCEMsg("EMsgERRMcliImproperUsageCombination","-c","-d");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   if ($DeleteFlag) {                   # no -d with -p
      printCEMsg("EMsgERRMcliImproperUsageCombination","-p","-d");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   $days_str = $opts{d};                # get days string 
   $Opt_DaysOfWeek = $TRUE;             # -d flag specified
   if ($days_str eq ""){                # no days for -d     
      printCEMsg("EMsgERRMcliMissingRequiredFlagOperand","-d");
      &print_usage;
      return ERRM_CLI_BAD_OPERAND;
      }
   }                                    # -d never required

if (defined $opts{t}) {                 # -t for times
   if ($RenameFlag) {                   # no -t with -c
      printCEMsg("EMsgERRMcliImproperUsageCombination","-c","-t");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   if ($DeleteFlag) {                   # no -t with -p
      printCEMsg("EMsgERRMcliImproperUsageCombination","-p","-t");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   $time_str = $opts{t};                # get time string
   $Opt_TimeOfDay = $TRUE;              # -t flag specified
   if ($time_str eq ""){                # no times for -t     
      printCEMsg("EMsgERRMcliMissingRequiredFlagOperand","-t");
      &print_usage;
      return ERRM_CLI_BAD_OPERAND;
      }
   }                                    # -t never required

if (defined $opts{r}) {                 # -r for return code
   if ($RenameFlag) {                   # no -r with -c
      printCEMsg("EMsgERRMcliImproperUsageCombination","-c","-r");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   if ($DeleteFlag) {                   # no -r with -p
      printCEMsg("EMsgERRMcliImproperUsageCombination","-p","-r");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   $ret_code_val = $opts{r};            # get return code
   $Opt_ReturnCode = $TRUE;             # -r flag specified
   $Opt_RetCodeCheck = $TRUE;           # opt flag specified
   if ($ret_code_val eq ""){            # no rc for -r     
      printCEMsg("EMsgERRMcliMissingRequiredFlagOperand","-r");
      &print_usage;
      return ERRM_CLI_BAD_OPERAND;
      }
   }                                    # -r never required

if (defined $opts{e}) {                 # -e for event type
   if ($RenameFlag) {                   # no -e with -c
      printCEMsg("EMsgERRMcliImproperUsageCombination","-c","-e");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   if ($DeleteFlag) {                   # no -e with -p
      printCEMsg("EMsgERRMcliImproperUsageCombination","-p","-e");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   $event_type = $opts{e};              # get the event type
   $Opt_EventType = $TRUE;              # -e flag specified
   if ($event_type eq ""){              # no event type for -e     
      printCEMsg("EMsgERRMcliMissingRequiredFlagOperand","-e");
      &print_usage;
      return ERRM_CLI_BAD_OPERAND;
      }

      # verify its a valid event type
      for ($j=0;$j<length($event_type);$j++) {
          # look at each event type specified
          $Code_Found = $FALSE;
          $tmp_event = substr($event_type,$j,1);

          # verify each type specified
          for ($i=0;$i<=$#EVENTTYPE;$i++) {
              if ($tmp_event eq $EVENTTYPE[$i]) {
                 if (defined $event_spec{$tmp_event}) {
                    printEMsg("EMsgchresponseInvalidEvent","-e",$event_type);
                    return ERRM_CLI_USER_ERROR;
                 }
                 else {
                    $event_code = $event_code | $EVENTTPCD[$i];
                    $Code_Found = $TRUE;
                    $event_spec{$tmp_event} = $TRUE;
                 }
              }
          }
          if (!$Code_Found){
             printEMsg("EMsgchresponseInvalidEvent","-e",$event_type);
             return ERRM_CLI_USER_ERROR;
          }
      }

   }                                    # -e never required

if (defined $opts{o}) {                 # -o for std out
   if ($RenameFlag) {                   # no -o with -c
      printCEMsg("EMsgERRMcliImproperUsageCombination","-c","-o");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   if ($DeleteFlag) {                   # no -o with -p
      printCEMsg("EMsgERRMcliImproperUsageCombination","-p","-o");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   $Opt_StdOut = $TRUE;                 # -o flag specified
   }                                    # -o never required

if (defined $opts{E}) {                 # -E for environment vars
   if ($RenameFlag) {                   # no -E with -c
      printCEMsg("EMsgERRMcliImproperUsageCombination","-c","-E");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   if ($DeleteFlag) {                   # no -E with -p
      printCEMsg("EMsgERRMcliImproperUsageCombination","-p","-E");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   $Opt_EnvList = $TRUE;                # opt flag specified
   $envlist = $opts{E};
   if ($envlist eq ""){                 # no command for -s
      printCEMsg("EMsgERRMcliMissingRequiredFlagOperand","-E");
      &print_usage;
      return ERRM_CLI_BAD_OPERAND;
      }
   }

if (defined $opts{u}) {                 # -u for UndefRes flag
   if ($RenameFlag) {                   # no -u with -c
      printCEMsg("EMsgERRMcliImproperUsageCombination","-c","-u");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   if ($DeleteFlag) {                   # no -u with -p
      printCEMsg("EMsgERRMcliImproperUsageCombination","-p","-u");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   $Opt_UndefRes = $TRUE;               # -u flag specified
   }

if (defined $opts{b}) {                 # -b for Batching flag
   if ($RenameFlag) {                   # no -b with -c
      printCEMsg("EMsgERRMcliImproperUsageCombination","-c","-b");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   if ($DeleteFlag) {                   # no -b with -p
      printCEMsg("EMsgERRMcliImproperUsageCombination","-p","-b");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   if ($Opt_EventType) {                # no -b with -e
      printCEMsg("EMsgERRMcliImproperUsageCombination","-e","-b");
      &print_usage;
      return ERRM_CLI_BAD_FLAG;
      }
   $Opt_Batching = $TRUE;               # -b flag specified
   }

return(0, $response_name, $action_name, $days_str, $time_str,
       $command, $ret_code_val, $event_code, 
       $new_name, $locator, $envlist);  # success
}   # end parse_cmd_line


#--------------------------------------------------------------------#
# print_usage : print the usage statement (syntax) to stdout.        #
#--------------------------------------------------------------------#
sub print_usage
{
&printIMsg("IMsgchresponseUsageErrEv");
}   # end print_usage