#! /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

MY_NAME=${0##*/}
OUTPUT_FORMAT="$1"
[ -z "$OUTPUT_FORMAT" ] && OUTPUT_FORMAT="ASCII"
[ "$OUTPUT_FORMAT" != "ASCII" -a "$OUTPUT_FORMAT" != "YCP" ] && { echo -en "\nUsage:\n$MY_NAME {ASCII|YCP}\n" 1>&2 ; exit 1 ; }

# Input:

# Create a temporary file:
TMP_DATA=$(mktemp -u /tmp/$MY_NAME.XXXXXX)
cat /dev/null >$TMP_DATA

# Function to extract entries from a description file with SANE syntax.
# Quoted quotation marks '\"' (happens in comments) are replaced by ' ':
Extract()
{ cat $1 | sed -e 's/\\"/ /g' | egrep -o '^[[:space:]]*:backend[[:space:]]*"[^"]*"|^[[:space:]]*:mfg[[:space:]]*"[^"]*"|^[[:space:]]*:model[[:space:]]*"[^"]*"|^[[:space:]]*:firmware[[:space:]]*"[^"]*"|^[[:space:]]*:interface[[:space:]]*"[^"]*"|^[[:space:]]*:usbid[[:space:]]*"0x[0-9A-Fa-f]*"[[:space:]]*"0x[0-9A-Fa-f]*"|^[[:space:]]*:status[[:space:]]*:[a-z]*|^[[:space:]]*:comment[[:space:]]*"[^"]*"'
}

# Process the SANE description files:
# At least the SANE description files must exist:
PACKAGE="sane-backends"
DESCRIPTION_FILES="/usr/share/sane/descriptions/*.desc"
ls $DESCRIPTION_FILES &>/dev/null || { echo "Error: Required SANE description files $DESCRIPTION_FILES not found." 1>&2 ; exit 3 ; }
# Write the package which is processed:
echo ":package \"$PACKAGE\"" >>$TMP_DATA
# Extract entries from SANE description files:
for DESCRIPTION_FILE in $DESCRIPTION_FILES
do Extract $DESCRIPTION_FILE
done >>$TMP_DATA

# Process the optional HPLIP external description file:
# The package hplip is installed by default.
PACKAGE="hplip"
DESCRIPTION_FILE="/usr/share/sane/descriptions-external/hpaio.desc"
if [ -r "$DESCRIPTION_FILE" ]
then echo ":package \"$PACKAGE\"" >>$TMP_DATA
     Extract $DESCRIPTION_FILE >>$TMP_DATA
else echo "Info: Cannot read $DESCRIPTION_FILE" 1>&2
fi

# Process the optional EPSON AVASYS (formerly EPSON KOWA) Image Scan external description file:
# The proprietary binary-only i386-only package iscan cannot be installed by default.
# The package iscan-free is not installed by default.
PACKAGE="iscan"
DESCRIPTION_FILE="/usr/share/sane/descriptions-external/epkowa.desc"
if [ -r "$DESCRIPTION_FILE" ]
then echo ":package \"$PACKAGE\"" >>$TMP_DATA
     Extract $DESCRIPTION_FILE >>$TMP_DATA
else echo "Info: Cannot read $DESCRIPTION_FILE" 1>&2
fi

# Process the collected data:

# Replace HTML tags:
sed -i -e 's/<[Bb][Rr]>/, /g' \
       -e 's/<[Pp]>/, /g' \
       -e 's/<[^>]*>/ /g' $TMP_DATA

# Condense multiple spaces and convert tabs to blanks:
sed -i -e 's/[[:space:]][[:space:]]*/ /g' $TMP_DATA

# Remove leading and trailing spaces:
sed -i -e 's/^[[:space:]]*//' \
       -e 's/[[:space:]]*$//' \
       -e 's/"[[:space:]]*/"/g' \
       -e 's/[[:space:]]*"$/"/' $TMP_DATA

# Convert the usbid values from '"vendor-id""product-id"' to '"vendor-id:product-id"'
# (note that '" "' was changed to '""' in the step before):
sed -i -e '/^:usbid/s/""/:/' $TMP_DATA

# Convert the status value to the usual string format:
sed -i -e 's/^:status :\(.*\)/:status "\1"/' $TMP_DATA

# Equalize different spelling of same manufacturers:
sed -i -e 's/"AGFA"/"Agfa"/g' \
       -e 's/"UMAX"/"Umax"/g' $TMP_DATA

# Change meaningless references to a meaningful reference:
sed -i -e 's/see link/see http:\/\/www.sane-project.org/g' \
       -e 's/See link/See http:\/\/www.sane-project.org/g' $TMP_DATA

# Output:

# Output header:
if [ "$OUTPUT_FORMAT" = "YCP" ]
then echo "[" 
else echo "PACKAGE|BACKEND|MANUFACTURER|MODEL|FIRMWARE|INTERFACE|USBID|STATUS|COMMENT"
fi

# Function to output one scanner entry:
Output()
{ if [ -n "$PACKAGE" -a -n "$BACKEND" -a -n "$MANUFACTURER" -a -n "$MODEL" -a -n "$STATUS" ]
  then [ -z "$FIRMWARE" ] && FIRMWARE='""'
       [ -z "$INTERFACE" ] && INTERFACE='""'
       [ -z "$USBID" ] && USBID='""'
       [ -z "$COMMENT" ] && COMMENT='""'
       if [ "$PACKAGE" = '"iscan"' -o "$PACKAGE" = '"iscan-free"' ]
       then if echo "$COMMENT" | egrep -q 'requires a DFSG non-free module|requires DFSG non-free'
            then PACKAGE='"iscan"'
            else PACKAGE='"iscan-free"'
            fi
       fi
       if [ "$OUTPUT_FORMAT" = "YCP" ]
       then echo -e "  \$[ \"package\":$PACKAGE,\n     \"backend\":$BACKEND,\n     \"manufacturer\":$MANUFACTURER,\n     \"model\":$MODEL,\n     \"firmware\":$FIRMWARE,\n     \"interface\":$INTERFACE,\n     \"usbid\":$USBID,\n     \"status\":$STATUS,\n     \"comment\":$COMMENT\n  ],"
       else echo "$PACKAGE|$BACKEND|$MANUFACTURER|$MODEL|$FIRMWARE|$INTERFACE|$USBID|$STATUS|$COMMENT" | tr -d '"'
       fi
  fi
}

# Make complete and seperated scanner entries:
# Package, backend, manufacturer and model should appear in this order.
# Interface, status and comment are optional and can appear in any order.
# There is no mandatory key which is always last.
# Therefore the values are collected until package or backend or manufacturer or model changes.
# When package or backend or manufacturer or model changes the values are output.
exec <$TMP_DATA
while read KEY VALUE
do expr "$VALUE" : '"[^"]*"$' &>/dev/null || { echo "Ignoring $VALUE because it has not the right syntax \"...\"." 1>&2 ; continue ; }
   case "$KEY" in
        :package) Output
                  PACKAGE="$VALUE"
                  BACKEND=""
                  MANUFACTURER=""
                  MODEL=""
                  FIRMWARE=""
                  INTERFACE=""
                  USBID=""
                  STATUS=""
                  COMMENT="" ;;
        :backend) Output
                  BACKEND=$( echo "$VALUE" | tr '[:upper:]' '[:lower:]' )
                  MANUFACTURER=""
                  MODEL=""
                  FIRMWARE=""
                  INTERFACE=""
                  USBID=""
                  STATUS=""
                  COMMENT="" ;;
        :mfg) Output
              MANUFACTURER="$VALUE"
              MODEL=""
              FIRMWARE=""
              INTERFACE=""
              USBID=""
              STATUS=""
              COMMENT="" ;;
        :model) Output
                MODEL="$VALUE"
                FIRMWARE=""
                INTERFACE=""
                USBID=""
                STATUS=""
                COMMENT="" ;;
        :firmware) FIRMWARE="$VALUE" ;;
        :interface) INTERFACE="$VALUE" ;;
        :usbid) USBID=$( echo "$VALUE" | tr '[:upper:]' '[:lower:]' ) ;;
        :status) STATUS="$VALUE" ;;
        :comment) COMMENT="$VALUE" ;;
        *) echo "Ignoring key $KEY" 1>&2 ;;
   esac
done

# Output the last scanner entry and a footer for YCP
Output
if [ "$OUTPUT_FORMAT" = "YCP" ]
then echo -e "  \$[]\n]"
fi

# Remove the temporary file
rm $TMP_DATA
exit 0