#! /bin/bash
#
# Johannes Meixner <jsmeix@suse.de>, 2004, 2005, 2006

#set -x

export PATH="/sbin:/usr/sbin:/usr/bin:/bin"
export LC_ALL="POSIX"
export LANG="POSIX"
umask 022

# When the package "sane" is installed, this file is created
# which lists all known USB scanners:
HAL_GLOBAL_FILE="/etc/hal/fdi/policy/10osvendor/70-scanner.fdi"
# This file is written by this script for those scanners
# which are not listed in HAL_GLOBAL_FILE:
HAL_LOCAL_FILE="/etc/hal/fdi/policy/10osvendor/80-scanner.fdi"

# Create temporary file names:
MY_NAME=${0##*/}
TMP_DATA=$(mktemp -u /tmp/$MY_NAME.XXXXXX)
TMP_DATA_RAW=$(mktemp -u /tmp/$MY_NAME.XXXXXX)

# Get the raw data (i.e. the SANE devices for the active scanners).
# Either it is specified as command line parameter $1
# (this is how YaST calls it to avoid duplicate time-consuming "scanimage" calls
# because it knows the SANE devices from its determine_active_scanners call)
# or (if $1 is empty) then run "scanimage" to determine the SANE devices:
if [ -n "$1" ]
then echo "$1" >$TMP_DATA_RAW
else MAXIMUM_WAIT="60"
     if [ -x /usr/bin/scanimage ]
     then scanimage -f '%d;' >$TMP_DATA_RAW &
          scanimagePID=$!
          for i in $( seq $MAXIMUM_WAIT )
          do ps $scanimagePID &>/dev/null || break
             sleep 1
          done
          if ps $scanimagePID &>/dev/null
          then kill -9 $scanimagePID &>/dev/null
          fi
     else echo "Cannot execute /usr/bin/scanimage" 1>&2
          exit 2
     fi
fi
# Split it into seperated lines, remove the SANE backend name, and remove duplicates
# (duplicates happen when different SANE backends are active for the same scanner):
tr ';' '\n' <$TMP_DATA_RAW | cut -d ':' -s -f 2- | sort -u >$TMP_DATA
# TMP_DATA should contain lines with plain device infos for scanners like
#   libusb:001:002
#   libusb:004:005
#   /dev/sg0
#   /dev/sg2
# A detailed syntax check is not done here because it happens later,
# see "Test for USB and SCSI scanners and ignore anything else" below.

# Write header to HAL_LOCAL_FILE
# and exit silently if this fails for whatever reason
# (e.g. no hal package installed):
cat /dev/null >$HAL_LOCAL_FILE || exit 0
echo '<?xml version="1.0" encoding="ISO-8859-1"?>' >>$HAL_LOCAL_FILE
echo '<deviceinfo version="0.2">' >>$HAL_LOCAL_FILE
echo '  <device>' >>$HAL_LOCAL_FILE
echo '' >>$HAL_LOCAL_FILE
echo '<!-- To grant access to USB scanners create entries like:' >>$HAL_LOCAL_FILE
echo '    <match key="info.category" string="usbraw">' >>$HAL_LOCAL_FILE
echo '      <match key="@info.parent:usb_device.vendor_id" int="0x1a2b">' >>$HAL_LOCAL_FILE
echo '        <match key="@info.parent:usb_device.product_id" int="0x3c4d">' >>$HAL_LOCAL_FILE
echo '          <append key="info.capabilities" type="strlist">scanner</append>' >>$HAL_LOCAL_FILE
echo '        </match>' >>$HAL_LOCAL_FILE
echo '      </match>' >>$HAL_LOCAL_FILE
echo '    </match>' >>$HAL_LOCAL_FILE
echo '"1a2b" and "3c4d" stand for the USB device IDs' >>$HAL_LOCAL_FILE
echo 'as displayed by the command /usr/sbin/lsusb -->' >>$HAL_LOCAL_FILE
echo '' >>$HAL_LOCAL_FILE

# Test and set scanner access permissions:
exec <$TMP_DATA
while read LINE
do # Test for USB and SCSI scanners and ignore anything else:
   if echo $LINE | grep -q '^libusb:[0-9][0-9]*:[0-9][0-9]*$'
   then # It is a USB scanner:
        # Determine the USB vendor and product IDs:
        BUS_DEVICE=$( echo $LINE | cut -d ':' -s -f 2- )
        VENDOR_PRODUCT=$( lsusb -s $BUS_DEVICE | grep -o 'ID [0-9A-Fa-f]*:[0-9A-Fa-f]*' | cut -b 4- )
        VENDOR=$( echo $VENDOR_PRODUCT | cut -d ':' -s -f 1 )
        PRODUCT=$( echo $VENDOR_PRODUCT | cut -d ':' -s -f 2 )
        # Test if this scanner is not already listed in the global HAL file:
        if ! grep -i -A 1 "usb_device.vendor_id\" int=\"0x$VENDOR\"" $HAL_GLOBAL_FILE | grep -q -i "usb_device.product_id\" int=\"0x$PRODUCT\""
        then # Write an entry to the local HAL file:
             echo '    <match key="info.category" string="usbraw">' >>$HAL_LOCAL_FILE
             echo "      <match key=\"@info.parent:usb_device.vendor_id\" int=\"0x$VENDOR\">" >>$HAL_LOCAL_FILE
             echo "        <match key=\"@info.parent:usb_device.product_id\" int=\"0x$PRODUCT\">" >>$HAL_LOCAL_FILE
             echo '          <append key="info.capabilities" type="strlist">scanner</append>' >>$HAL_LOCAL_FILE
             echo '        </match>' >>$HAL_LOCAL_FILE
             echo '      </match>' >>$HAL_LOCAL_FILE
             echo '    </match>' >>$HAL_LOCAL_FILE
             echo '' >>$HAL_LOCAL_FILE
        fi
   fi
   if echo $LINE | grep -q '^/dev/sg[0-9][0-9]*$'
   then # It is a SCSI scanner:
        # Test if this scanner does not show up as "scanner".
        # There are two know manufacturers where this happens: "HP" and "EPSON".
        # Some (all?) of their SCSI scanners show up as as "processor"
        # (because those devices do not support the SCSI scanner protocol
        # but only some kind of generic SCSI protocol):
        LSSCSI_LINE=$( lsscsi -g | grep $LINE )
        if ! echo $LSSCSI_LINE | tr -s ' ' | cut -d ' ' -f2 | grep -q -i 'scanner'
        then # Test for the particular manufacturer:
             if echo $LSSCSI_LINE | tr -s ' ' | cut -d ' ' -f3 | grep -q -i 'HP'
             then # Write a HP entry to the local HAL file:
                  echo '    <match key="info.category" string="scsi_generic">' >>$HAL_LOCAL_FILE
                  echo '      <match key="@info.parent:scsi.type" string="processor">' >>$HAL_LOCAL_FILE
                  echo '        <match key="@info.parent:scsi.vendor" string="HP">' >>$HAL_LOCAL_FILE
                  echo '          <append key="info.capabilities" type="strlist">scanner</append>' >>$HAL_LOCAL_FILE
                  echo '        </match>' >>$HAL_LOCAL_FILE
                  echo '      </match>' >>$HAL_LOCAL_FILE
                  echo '    </match>' >>$HAL_LOCAL_FILE
                  echo '' >>$HAL_LOCAL_FILE
             fi
             if echo $LSSCSI_LINE | tr -s ' ' | cut -d ' ' -f3 | grep -q -i 'EPSON'
             then # Write an EPSON entry to the local HAL file:
                  echo '    <match key="info.category" string="scsi_generic">' >>$HAL_LOCAL_FILE
                  echo '      <match key="@info.parent:scsi.type" string="processor">' >>$HAL_LOCAL_FILE
                  echo '        <match key="@info.parent:scsi.vendor" string="EPSON">' >>$HAL_LOCAL_FILE
                  echo '          <append key="info.capabilities" type="strlist">scanner</append>' >>$HAL_LOCAL_FILE
                  echo '        </match>' >>$HAL_LOCAL_FILE
                  echo '      </match>' >>$HAL_LOCAL_FILE
                  echo '    </match>' >>$HAL_LOCAL_FILE
                  echo '' >>$HAL_LOCAL_FILE
             fi
        fi
   fi
done

# Write footer to HAL_LOCAL_FILE:
echo '  </device>' >>$HAL_LOCAL_FILE
echo '</deviceinfo>' >>$HAL_LOCAL_FILE

# Remove the temporary files:
rm $TMP_DATA $TMP_DATA_RAW
exit 0

