#!/bin/sh

# Copyright(C) 2005-2017
#
# This is proprietary information of
# Crypto-Pro company.
#
# Any part of this file can not be copied,
# corrected, translated into other languages,
# localized or modified by any means,
# compiled, transferred over a network from or to
# any computer system without preliminary
# agreement with Crypto-Pro company

S_OK=0
ERROR_DUPLICATED_ALL_FIELDS=1
ERROR_DUPLICATED_VENDOR_AND_PRODUCT=2
ERROR_CORRUPTED_PLIST=3
ERROR_BAD_ARGS=4
ERROR_REGISTRATION_WAS_NOT_FOUND=6

# $1 - VendorID $2 - ProductID $3 - FriendlyName 
check_previous_registration()
{
  res=$S_OK
  vendor_str_find_arr=`echo "$VendorId_list" | grep -in $1 | awk -F":" '{print $1}'`

  for i in $vendor_str_find_arr
  do
    str_in_section_productId=`echo "$ProductId_list" | sed "${i}q;d" | grep -i "$2"`
    if test -n "$str_in_section_productId"; then
       # ищем строгое соответсвие FriendlyName
       str_in_section_friendly_name=`echo "$FriendlyName_list" | sed "${i}q;d" | grep -i "$3$"`
       if test -z "$str_in_section_friendly_name"; then
          res=$ERROR_DUPLICATED_VENDOR_AND_PRODUCT
       else
          res=$ERROR_DUPLICATED_ALL_FIELDS
       fi

       if test $res -eq $ERROR_DUPLICATED_ALL_FIELDS; then
          return $res
       fi
    fi
  done

  return $res
}

# $1 - string $2 - section 
add_string_to_section()
{
  line=`sed -n "/$2/{=;}" $tmpFile`
  line=`expr $line + 2`
  sed -i.old -e "$line""i\\
<string>$1<\/string>" $tmpFile
  rm -f "$tmpFile.old"
}

print_help()
{
  echo "
  using ccid_reg.sh: 
  ccid_reg.sh [command] [arguments]:

  select [command] from:
  -help         Print this help
  -add          ccid_reg.sh -add <path_to_Info.plist> <VID> <PID> <Name>
  -list         ccid_reg.sh -list <path_to_Info.plist>
  -del          ccid_reg.sh -del <path_to_Info.plist> <VID> <PID> <Name>"
}

list_registrations()
{
  pre_command_action
  ret=$?
  if test $ret -ne $S_OK; then
    return $ret
  fi 

  # создаем "массивы" для ускорения печати
  i=0
  for tmp in $VendorId_list; do
    eval VendorIdArr_$i=$tmp
    i=`expr $i + 1`
  done

  IFS_BAK=$IFS
  IFS=$'
'
  i=0
  for line in $FriendlyName_list; do
    eval FriendlyNameArr_$i=\"$line\"
    i=`expr $i + 1`
  done
  IFS=$IFS_BAK
  IFS_BAK=
 
  i=0
  for tmp in $ProductId_list; do
    eval ProductIdArr_$i=$tmp
    i=`expr $i + 1`
  done

  i=0
  while test $i -lt $nVendorID; do
    eval echo "\$VendorIdArr_$i:\$ProductIdArr_$i \$FriendlyNameArr_$i" | sed 's/0x//g'
    i=`expr $i + 1`
  done
}  

pre_command_action()
{ 
  FileContent=`cat $tmpFile`
  VendorId_list=`echo "$FileContent" | sed -n "/VendorID/,/<\/array>/p" | grep -Fv -e "<key>" -e array|sed 's/<\/\{0,1\}string>//g'`
  ProductId_list=`echo "$FileContent" | sed -n "/ProductID/,/<\/array>/p" | grep -Fv -e "<key>" -e array|sed 's/<\/\{0,1\}string>//g'`
  FriendlyName_list=`echo "$FileContent" | sed -n "/FriendlyName/,/<\/array>/p" | grep -Fv -e "<key>" -e array|sed 's/<\/\{0,1\}string>//g'`
  nVendorID=`echo "$VendorId_list" | wc -l`
  nProductID=`echo "$ProductId_list" | wc -l`
  nFriendlyName=`echo "$FriendlyName_list" | wc -l`
  posVendorID=`echo "$FileContent" | sed -n "/VendorID/{=;}"`
  posProductID=`echo "$FileContent" | sed -n "/ProductID/{=;}"`
  posFriendlyName=`echo "$FileContent" | sed -n "/FriendlyName/{=;}"`

  if test -z "$VendorId_list" -o -z "$ProductId_list" -o -z "$FriendlyName_list"; then
    return $ERROR_CORRUPTED_PLIST
  fi

  if test "$nVendorID" -ne "$nProductID" -o "$nVendorID" -ne "$nFriendlyName" -o "$nProductID" -ne "$nFriendlyName"; then
    echo "error, $plist_file is corrupted"
    echo "number of lines in sections : VendorID - $nVendorID, ProductID - $nProductID, FriendlyName - $nFriendlyName"
    return $ERROR_CORRUPTED_PLIST
  fi

  return $S_OK
}

# $1 - Info.plist , $2 - VendorID , $3 - ProductID , $4 - Friendly Name
add_registration()
{
  pre_command_action
  ret=$?
  if test $ret -ne $S_OK; then
    return $ret
  fi

  VID=`echo $2 | sed 's/0x//g'`
  PID=`echo $3 | sed 's/0x//g'`
  name="$4"
  check_previous_registration $2 $3 "$name" 
  check_registration_code=$?
  if test $check_registration_code -ne $S_OK; then
    case $check_registration_code in
      $ERROR_DUPLICATED_ALL_FIELDS)  
        echo "  same device \"$VID:$PID $name\" already registered";;
      $ERROR_DUPLICATED_VENDOR_AND_PRODUCT)  
        echo "  device with same VID:PID \"$VID:$PID\" already exists";;
    esac

    return $check_registration_code
  fi

  add_string_to_section $2 VendorID 
  add_string_to_section $3 ProductID 
  add_string_to_section "$4" FriendlyName 
   
  return $S_OK
}

# $1 - Info.plist , $2 - VendorID , $3 - ProductID , $4 - Friendly Name 
del_registration()
{
  pre_command_action
  ret=$?
  if test $ret -ne $S_OK; then
    return $ret
  fi

  vendor_str_find_arr=`echo "$VendorId_list" | grep -in $2 | awk -F":" '{print $1}'`

  if test -z "$vendor_str_find_arr"; then
     echo "  error, string $2 to delete was not found"
     return $ERROR_REGISTRATION_WAS_NOT_FOUND
  fi

  ret=$ERROR_REGISTRATION_WAS_NOT_FOUND
  for i in $vendor_str_find_arr; do
    str_in_section_productId=`echo "$ProductId_list" | sed "${i}q;d" | grep -i "$3"`
    str_in_section_friendly_name=`echo "$FriendlyName_list" | sed "${i}q;d" | grep -i "$4"`
    if test -n "$str_in_section_productId" && test -n "$str_in_section_friendly_name"; then
      sed -i.backup  `expr $i + $posVendorID + 1`d $tmpFile
      sed -i.backup  `expr $i + $posProductID`d $tmpFile
      sed -i.backup  `expr $i + $posFriendlyName - 1`d $tmpFile
      rm -f "$tmpFile.backup"
      ret=$S_OK
      break
    fi
  done

  if test $ret -ne $S_OK; then
    eval echo "error, cannot find $2:$3 $4 to delete" | sed 's/0x//g'
  fi

  return $ret
}

# $1 - cmd , $2 - Info.plist , $3 - VendorID, $4 - ProductID , $5 - Friendly Name
parse_cmd_line()
{
  if test -z "$1" || test "$1" = "--help" || test "$1" = "-help"; then
    print_help
    return $S_OK
  fi

  if test $1 != "-add" && test $1 != "-list" && test $1 != "-del"; then
    echo "  error, wrong command"
    echo "  for more information use ccid.reg.sh -help" 
    return $ERROR_BAD_ARGS
  fi

  if (test -z "$5" && test $1 != "-list") || (test $1 = "-list" && test -z "$2"); then
    echo "  error, too few arguments for command $1"
    echo "  for more information use ccid.reg.sh -help"
    return $ERROR_BAD_ARGS
  fi

  if test ! -f "$2"; then
    echo "  error, file $2 doesn't exist" 
    return $ERROR_BAD_ARGS
  fi
  
  if test $1 != "-list"; then
    tmpFile=`mktemp /tmp/tmpInfo_XXXXXXXXXX`
    cp "$2" $tmpFile
  else
    tmpFile="$2"
  fi

  case $1 in
    "-add")
      add_registration $tmpFile $3 $4 "$5";;
    "-list")
      list_registrations $tmpFile 
      return $?;;
    "-del")
      del_registration $tmpFile $3 $4 "$5";;
  esac
 
  res=$?
  if test $res -eq $S_OK; then
    cp $tmpFile "$2"
  fi
  
  rm -f $tmpFile  
  return $res
}

id_to_upper()
{
  # не забываем вернуть префикс в нормальный регистр
  echo $1 | tr [:lower:] [:upper:] | sed s/0X/0x/
}

command=$1
plist_file="$2"
# приводим VendorID и productID к uppercase
vendorID=`id_to_upper $3`
productID=`id_to_upper $4`
friendly_name="$5"
parse_cmd_line $command "$plist_file" $vendorID $productID "$friendly_name"

res=$?

exit $res
