#!/bin/bash
# ###########################################################################
# Copyright (c) 2011, Dell Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#    * Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above copyright
#      notice, this list of conditions and the following disclaimer in the
#      documentation and/or other materials provided with the distribution.
#    * Neither the name of Dell Inc. nor the names of its contributors
#      may be used to endorse or promote products derived from this software
#      without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL DELL INC. BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ###########################################################################
# Authors: Chris A. Poblete
# Version: 1.0.0
# ###########################################################################

MYNAME=`basename $0`
WSENUMMAXELEM=512

# source function library
. /etc/wsl/wsl-functions

usage() {
  fUsageheader
  cat <<EOF
USAGE: $MYNAME CLASS METHOD [PARAM1=VAL1 PARAM2=VAL2 ...] [OPTIONS]

Sends SOAP message with WS-MAN INVOKE command. This script may accept only 
derived leaf classes unless you provide a CQL filter that can return a 
single instance. CLASS may be a class name or an absolute class URI.
CLASS should be the first input and Method the second input.
Enclose the value in double quotes when the value contains space.

[OPTIONS]
-filter "CQL"       - Apply CQL statement filter to enumeration
-inst FILENAME      - Contains class instance EPR 
-ns NAMESPACE       - Explicitly add the NAMESPACE selector
-raw FILENAME       - Use raw input for the method contained in the filename

If CLASS has more than one instance, use the -filter option to filter the 
enumeration to a single instance. Alternatively, use the -inst option to 
provide the instance EPR in a previous enumeration.

PARAM=FILE:FILENAME
If Value is of type EPR (endpoint reference), you can provide a file
that contains an instance EPR. An EPR contains EndpointReference
element. An example of this is:
  ManagedElement=FILE:compsys.xml

PARAM=RFILE:FILENAME
If Value could not be passed through command line perhaps due to special
characters of contain line breaks, you can provide it in a file with
RFILE prefix. An example of this is a certificate value:
  Certificate=RFILE:newad.cer

${CommonUsage1}
EOF
  $WSCOLORNORM
  exit 1
}

fCheckReqsOrUsage

[ $# -lt 2 ] && usage
while [ ! -z "$1" ]; do
  case "$1" in
    -h|-help|help ) usage
      ;;
    -i|-inst ) shift; InstanceFile="$1"
      ;;
    -f|-filter ) shift; CQL="$1"
      ;;
    -n|ns ) shift; WSNS="$1"
      ;;
    -r|-raw ) shift; RAW="$1"
      ;;
    * ) echo "$1" | grep '=' >/dev/null 2>&1
      if [ $? -ne 0 ]; then
        [ -z "${CLASS}" ] && export CLASS="$1" && shift && continue
        [ -z "${METHOD}" ] && export METHOD="$1" && shift && continue
      else
        Name=$(echo "$1" | cut -d '=' -f1 )
        Value=$(echo "$1" | cut -d '=' -f2- )
        echo "${Value}" | grep "^FILE:" >/dev/null 2>&1
        if [ $? -eq 0 ]; then
          filename=$(echo "${Value}" | cut -d ':' -f2- )
          echo "using ${filename} to extract EPR XML for parameter ${Name}"
          fExtractEPRXML ${filename}
          Value="${EPRXML}"
        else
          echo "${Value}" | grep "^RFILE:" >/dev/null 2>&1
          if [ $? -eq 0 ]; then
            filename=$(echo "${Value}" | cut -d ':' -f2- )
            echo "using ${filename} to extract EPR XML for parameter ${Name}"
            Value=$(cat ${filename})
          fi
        fi
        PARAMLIST="${PARAMLIST}<p:${Name}>${Value}</p:${Name}>"
      fi
      ;;
  esac
  shift
done

[ ! -z "${PARAMLIST}" ] && [ ${OUTLEVEL} -ge 3 ] && echo -en "## ${PARAMLIST}\n\n"

# initializations
fGetTarget
fSetWGET
fNormalizeClass

[ ! -z "${CQL}" ] && CQLQUERY="<wsman:Filter Dialect='http://schemas.dmtf.org/wbem/cql/1/dsp0202.pdf'>${CQL}</wsman:Filter>"

if [ ! -z "${WSNS}" ]; then
REQSELECTORS=`cat <<EOF
  <wsman:SelectorSet>
    <wsman:Selector Name="__cimnamespace">${WSNS}</wsman:Selector>
  </wsman:SelectorSet>
EOF`
fi

dopullX() {
  fGetUUID
  fReqRspNext
  cat <<EOF >${REQUESTFILE}
${WSENVELOPEHEADER}
  <s:Header>
    <wsa:Action s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/09/enumeration/Pull</wsa:Action>
    ${WSCOMMONHEADER}
    <wsman:ResourceURI s:mustUnderstand="true">${CLASS}</wsman:ResourceURI>
    <wsa:MessageID s:mustUnderstand="true">${UUID}</wsa:MessageID>
    <wsa:ReplyTo>
      <wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
    </wsa:ReplyTo>
  </s:Header>
  <s:Body>
    <wsen:Pull>
      <wsen:EnumerationContext>${CONTEXT}</wsen:EnumerationContext>
      ${WSPULLMAXELEMSTR}
    </wsen:Pull>
  </s:Body>
</s:Envelope>
EOF
  fNormalizeXML ${REQUESTFILE}
  fDumpRequestFile
  fSendRequest
  fNormalizeXML ${RESPONSEFILE}
  unset CONTEXT ; fGetFlatValueOfSingle ${RESPONSEFILE} N "EnumerationContext" ; export CONTEXT=${PVALUE}
  grep 'PullResponse' ${RESPONSEFILE} 2>&1 >/dev/null
  export STAT=$?
}

doenumerateX() {
  fGetUUID
  fReqRspNext
  cat <<EOF >${REQUESTFILE}
${WSENVELOPEHEADER}
  <s:Header>
    <wsa:Action s:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/09/enumeration/Enumerate</wsa:Action>
    ${WSCOMMONHEADER}
    <wsman:ResourceURI s:mustUnderstand="true">${CLASS}</wsman:ResourceURI>
    <wsa:MessageID s:mustUnderstand="true">${UUID}</wsa:MessageID>
    <wsa:ReplyTo>
      <wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
    </wsa:ReplyTo>
    ${REQSELECTORS}
  </s:Header>
  <s:Body>
    <wsen:Enumerate>
      ${WSENUMOPTIMIZEDSTR}
      ${WSENUMMAXELEMSTR}
      ${EPR}
      ${CQLQUERY}
    </wsen:Enumerate>
  </s:Body>
</s:Envelope>
EOF
  fNormalizeXML ${REQUESTFILE}
  fDumpRequestFile
  fSendRequest
  fNormalizeXML ${RESPONSEFILE}
  unset CONTEXT ; fGetFlatValueOfSingle ${RESPONSEFILE} N "EnumerationContext" ; export CONTEXT=${PVALUE}
  grep 'EnumerateResponse' ${RESPONSEFILE} 2>&1 >/dev/null
  export STAT=$?
}

doenumerate() {
  doenumerateX
  [ ${OUTLEVEL} -ge 3 ] && ( $WSCOLORRSP; [ ${STAT} -ne 0 ] && $WSCOLORERR ; cat ${RESPONSEFILE} ; $WSCOLORNORM )
  while [ ! -z "${CONTEXT}" ]; do
    dopullX
    [ ${OUTLEVEL} -ge 3 ] && ( $WSCOLORRSP; [ ${STAT} -ne 0 ] && $WSCOLORERR ; cat ${RESPONSEFILE} ; $WSCOLORNORM )
    echo "(${CONTEXT})"
  done
}

doinvoke() {
  fGetUUID
  fReqRspNext

  if [ ! -z "${RAW}" ]; then
    PARAMBODY=`cat ${RAW}`
  else
    PARAMBODY=`cat <<EOF
      <p:${METHOD}_INPUT xmlns:p="${RURI}">
        ${PARAMLIST}
     </p:${METHOD}_INPUT>
EOF`
  fi

cat <<EOF >${REQUESTFILE}
${WSENVELOPEHEADER}
  <s:Header>
    <wsa:Action s:mustUnderstand="true">${RURI}/${METHOD}</wsa:Action>
    ${WSCOMMONHEADER}
    <wsman:ResourceURI s:mustUnderstand="true">${RURI}</wsman:ResourceURI>
    <wsa:MessageID s:mustUnderstand="true">${UUID}</wsa:MessageID>
    <wsa:ReplyTo>
      <wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
    </wsa:ReplyTo>
    ${EPRSELECTORSTR}
  </s:Header>
  <s:Body>
    ${PARAMBODY}
  </s:Body>
</s:Envelope>
EOF
  fNormalizeXML ${REQUESTFILE}
  fDumpRequestFile
  fSendRequest
  fNormalizeXML ${RESPONSEFILE}
  grep "_OUTPUT" ${RESPONSEFILE} 2>&1 >/dev/null
  export STAT=$?
}

if [ ! -z "${InstanceFile}" ]; then
  fGetEPRSELECTOR ${InstanceFile}
else
  [ ${OUTLEVEL} -ge 3 ] && echo "NOTE: Enumerate operation may take time to reply."
  EPR="<wsman:EnumerationMode>EnumerateEPR</wsman:EnumerationMode>"
  doenumerate
  fGetEPRSELECTOR ${RESPONSEFILE}
fi

if [ ! -z "${EPRSELECTORSTR}" ]; then
  [ ${OUTLEVEL} -ge 3 ] && echo "NOTE: Invoke operation may take time to reply."
  doinvoke 
fi

fDisplayResponse ${RESPONSEFILE}

/bin/cp ${RESPONSEFILE} ${RETURNFILE}
[ ${OUTLEVEL} -ge 3 ] && echo "Output is saved to ${RETURNFILE}"
exit ${STAT} 

# ###########################################################################
# End of Code
# ###########################################################################
