#! /bin/bash
#
# Copyright (c) 2000 SuSE GmbH Nuernberg, Germany. All rights reserved.
# Versi terjemahan dari inertz@yahoo.com
# tajuk:pnpmodem

FRUN="/var/run/modem.conf"
FLOCK="/var/lock/modem.conf"
FLOG="/var/log/modem.conf"
FPNP="/etc/isapnp.conf"
FSERIAL="/sbin/init.d/serial"
SEP="|"
ALLSILENT='n'
PROCCMD1="/sbin/lspci -vvn"
PROCCMD2="/sbin/lspci"
PCISTARTTAG1="Class 0700:"
PCISTARTTAG2="Class 0780:"
PCIENDTAG="^$"
SERCON="Serial controller"
PCIIRQID="IRQ"
PCIIRQFNO=7
PCIIOID="I/O ports at"
PCIIOFNO=6
PNPDUMPCMD="/sbin/pnpdump -c"
ISAPNPCMD="/sbin/isapnp"
ISASTARTTAG="(CONFIGURE"
ISAENDTAG="(ACT Y)"
ISAIOID1='^.*IO.*BASE '
ISAIOID2=')).*$'
ISAIRQID1='^.*IRQ '
ISAIRQID2=' (.*$'
ISANAMETAG='NAME'
TYPEPCI="pci"
TYPEISA="isa"
declare -ix DEVICENO=5
UART="16550A"
SERFLAGS="^fourport"
declare -i MODCOUNT=0
VERSEP='----------------------------------------------------------'
STDIO1="0x03f8"
STDIO2="0x02f8"
STDIO3="0x03e8"
STDIO4="0x02e8"
STDIRQ1="irq 3"
STDIRQ2="irq 4"
ITEM1="modem"
ITEM2="fax"
ITEM3="56k"
SLASH=':'
base=${0##*/}
FSERAILHEAD="    # Berikut ditambah sendiri oleh $base"

function printhelp()
{
    echo "${base}:"
    echo "   cuba meneka modem pnp serta "
    echo "   serta cuba untuk mengesan configurasi modem pnp"
    echo "   Langkah -langkah:"
    echo "      cari pcimodem dan laporkan sekiranya terdapat winmodem"
    echo "      cari modem isapnp"
    echo "      menkonfigurasi 'dev/ttyS5' atau lebih utk modem yang dijumpai"
    echo "      periksa samaada modem beroperasi"
    echo "      konfigurasi disimpan di '/sbin/init.d/serial'"
    echo
    echo "   usage:"
    echo "      ${base}"
    echo "         mulakan skript dalam mod interaktif"
    echo "      ${base} -s"
    echo "         versi senyap "
    echo "         modem dijumpai dan berfungsi"
    echo "      ${base} [-h|--help|-?]"
    echo "         cetak mesej ini"
    echo
    echo "   Skrip akan menjanakan '/var/log/modem.conf'"
    echo "   dimana boleh digunakan untuk pemasangan SuSE"
    echo "   sekiranya terdapat masalah modem"
}


function cleanup()
{
    if [ -z $TMPFILE1 ]; then
	return
    fi
    if [ -f $TMPFILE1 -a -w $FLOG ]; then
	echo $VERSEP  >> $FLOG 
	echo "modem dijumpai:" >> $FLOG
	cat $TMPFILE1 >> $FLOG 
	echo $VERSEP  >> $FLOG
	echo "${PROCCMD1}:" >> $FLOG 
	lspci -vvn >> $FLOG
	if [ -f $FPNP ]; then
	    echo $VERSEP  >> $FLOG
	    echo "${FPNP}:" >> $FLOG
	    cat ${FPNP}  >> $FLOG
	fi
    fi
    rm -f $TMPFILE1
    rm -f $TMPFILE2
    rm -f $FRUN
    if [ -f $FLOCK ]; then
	rm -f $FLOCK
    fi
    if [ -f $TMPFILE3 ]; then
	rm -f $TMPFILE3
    fi
    if [ -f $TMPFILE4 ]; then
	rm -f $TMPFILE4
    fi
}

trap cleanup EXIT SIGHUP SIGINT SIGPIPE SIGTERM SIGIO

function log()
{
	# mesej akan dilog
	ECHOOPT=""
	SILENTOPT="n"
	CHECKOPT='y'
	DATE=''
	while [ $CHECKOPT = 'y' ]; do
	    case $1 in
		-e|-n|-ne|-ne)
		   ECHOOPT=$1
		   shift
		   ;;
		-s)
		   SILENTOPT="y"
		   shift
 		   ;;
		*)
		   CHECKOPT='n'
		   ;;
	    esac
	done
	echo -e ${DATE} "$@" >> ${FLOG}
	if [ $SILENTOPT = "n" -a $ALLSILENT != 'y' ]; then
	    echo -e $ECHOOPT "$@"
	fi
}

function getpcidata()
{
	COUNT=$1
	shift
	AMODEM=$@
	$PROCCMD1 | sed -n "/${AMODEM}/ \
	{:x;p;n;/${PCIENDTAG}/q;bx}" | \
	{
	    IRQ="0"
	    IO="0"
	    while read aline; do
		case ${aline} in
		  *${PCIIRQID}*)
			IRQ=`echo ${aline} | cut -d" " -f$PCIIRQFNO`
			;;
		  *${PCIIOID}*)
			IO="0x"`echo ${aline} | cut -d" " -f$PCIIOFNO`
			;;
		  *)
		    ;;
		esac
	    done
	    # no${SEP}type${SEP}id${SEP}irq${SEP}io${SEP}ok
	    echo ${COUNT}${SEP}${TYPEPCI}${SEP}${AMODEM}${SEP}${IRQ}${SEP}${IO}${SEP}${TESTNO} >> ${TMPFILE1}
	}
}


function getallpcidata()
{
	$PROCCMD1 | grep "${PCISTARTTAG1}" | cut -d" " -f 1 | while read line; do
		getpcidata $MODCOUNT $line
		MODCOUNT=$MODCOUNT+1
	done
	$PROCCMD1 | grep "${PCISTARTTAG2}" | while read line; do
		businfo=`echo ${line} | cut -d" " -f1`
		log $FOUNDCLASS780
		log -s businfo=${businfo}
		log -s `$PROCCMD1 | grep ${businfo}`
		log `$PROCCMD2 | grep ${businfo}`
		if [ $ALLSILENT != 'y' ]; then	
		    echo -e ${WINMODEMINFO}${FAILED}
		fi
	done
}

function guessisamodem()
{
    AMODEM=$@
    #periksa port standard dan irq
    cat ${TMPFILE4} | tr '/' $SLASH | sed -n "/${AMODEM}/ \
	{:x;p;n;/${ISAENDTAG}/q;bx}" | \
	while read line; do
	    echo $line  | grep -i "$STDIO1\|$STDIO2\|$STDIO3\|$STDIO4\|$STDIRQ1\|$STDIRQ2\|$ITEM1\|$ITEM2\|$ITEM3" &>/dev/null
	    if [ $? -eq 0 ]; then
		return 1
	    fi
	done
    if [ $? -ne 1 ]; then
	return 1
    fi
}

function getisadata()
{
    COUNT=$1
    shift
    AMODEM=$@
    guessisamodem $AMODEM
    if [ $? -ne 0 ]; then
	    echo not a modem
	    return 1
    fi
    cat ${TMPFILE4} | tr '/' $SLASH | sed -n "/${AMODEM}/ \
	{:x;p;n;/${ISAENDTAG}/q;bx}" | \
    {
	IRQ="0"
	IO="0"
	while read aline; do
	    dummy=`echo ${aline} | \
		sed -n "s/${ISAIRQID1}\(.*\)${ISAIRQID2}/\1/p"`
	    if [ ! -z $dummy ]; then
		IRQ=$dummy
	    fi
	    dummy=`echo ${aline} | \
		sed -n "s/${ISAIOID1}\(.*\)${ISAIOID2}/\1/p"`
	    if [ ! -z $dummy ]; then
		IO=$dummy
	    fi
	done
	# no${SEP}type${SEP}id${SEP}irq${SEP}io${SEP}ok
	echo ${COUNT}${SEP}${TYPEISA}${SEP}${AMODEM}${SEP}${IRQ}${SEP}${IO}${SEP}${TESTNO} >> ${TMPFILE1}
	#echo isamodem write: ${COUNT}${SEP}${TYPEISA}${SEP}${AMODEM}${SEP}${IRQ}${SEP}${IO}${SEP}${TESTNO} 
    }
}

function getallisadata()
{
	if [ ! -f $FPNP ]; then
	    log $ISADUMPMSG
	    eval $PNPDUMPCMD > $TMPFILE4
	    echo $VERSEP  >> $FLOG 
	    echo output of PNPDUMPCMD: >> $FLOG 
	    $ISAPNPCMD $TMPFILE4 >> $FLOG 2>&1
	    if [ $? -ne 0 ]; then
		log $FAILED
	    fi
	    cp $TMPFILE4 $FPNP
	    log $DONE
	fi
	echo -e '^.*#\n^ *$' | grep -v -f - $FPNP > $TMPFILE4
	#grep -v "^.*#" $FPNP | grep -v "^ *$" > $TMPFILE4
	grep "${ISASTARTTAG}" $TMPFILE4 | while read line; do
		line=`echo $line | tr '/' $SLASH`
		getisadata $MODCOUNT $line
	done
}

function getmodemname()
{
    case $1 in
	$TYPEPCI)
	    MODEMNAME=`${PROCCMD2} | grep $2 | cut -d' ' -f4-`
	    ;;
	$TYPEISA)
	    MODEMNAME=`cat ${TMPFILE4} | tr '/' ':' | \
	    sed -n "/${2}/{:x;n;/${ISANAMETAG}/by;bx;:y;s/[^\"]*\(.*\"\).*/\1/p;}"`
	    ;;
	*)
	    log "$INTERR (silap modem)"
	    ;;
    esac
}

function settestresult()
{
    MID=$1
    RES=$2
    #no${SEP}type${SEP}id${SEP}irq${SEP}io${SEP}ok"
    #line=`grep ${MID} ${TMPFILE1}`
    #echo ${line%|*}
    TMPFILE5=`mktemp -q /tmp/$base.XXXXXX`
    if [ $? -ne 0 ]; then
	log "Tidak dapat buat fail sementara(temp)..."
	exit 1
    fi
    sed "/$MID/s/^\(.*|\).*$/\1${RES}/" $TMPFILE1 > $TMPFILE5
    mv $TMPFILE5 $TMPFILE1
}

function querysetserial()
{
	DEVNO=$1
	IO=$2
	IRQ=$3
	ID=$4
	TYPE=$5
	MNAME=$6
	log -ne ${CONDEV1}${MNAME}${CONDEV5}
	log -s "${CONDEV6}${ID}${CONDEV7}${TYPE}${CONDEV2}${IO}\
		${CONDEV3}$IRQ${CONDEV4}/dev/ttyS${DEVNO}"
	if [ $ALLSILENT != 'y' ]; then	
	    read repl <&1
	    log -s "reply=$repl"
	fi
	test ! -z ${repl##* } || repl=$REPLLY
	if [ $repl = $REPLLY -o $repl = $REPLCY ]; then
		SETSERIAL="/sbin/setserial /dev/ttyS${DEVNO} irq $IRQ port ${IO} uart ${UART} ${SERFLAGS}"
		SERCHECK="/dev/ttyS${DEVNO} irq $IRQ port ${IO} uart ${UART}"
		log -s "${SETSERIAL}"
		if [ ${IO} = ${STDIO3} ]; then
		    eval "/sbin/setserial /dev/ttyS2 port 0"
		fi
		if [ ${IO} = ${STDIO4} ]; then
		    eval "/sbin/setserial /dev/ttyS3 port 1"
		fi
		eval ${SETSERIAL}
		if [ $? -eq 0  ]; then
		    testddev /dev/ttyS${DEVNO}
		    if [ $? -ne 0 ]; then
			log $SETSERIALFAILED
			settestresult $ID $TESTFAILED
			SETSERIAL="/sbin/setserial /dev/ttyS${DEVNO} irq 0 port 0 uart unknown"
			eval ${SETSERIAL}
			return 1
		    fi
		    writetoserial "${SETSERIAL}" "${SERCHECK}"
		    if [ $? -ne 0 ]; then
			settestresult $ID $TESTNOTWROTE
		    else
			settestresult $ID $TESTOK
		    fi
		else
		    log $SETSERIALFAILED
		fi
	else
		log -e $SETSERIALABORT
		return 1
	fi
}

function setserialall()
{
	export IFS="|"
	unsetmyserials
	# no${SEP}type${SEP}id${SEP}irq${SEP}io${SEP}ok
	cat ${TMPFILE1} | while read COUNT TYPE MODEMID IRQ IO RES; do
		#echo "reading: ${COUNT}${SEP}${TYPEPCI}${SEP${MODEMID}${SEP}${IRQ}${SEP}${IO}${SEP}${RES}"
		if [ x${COUNT:0:1} = 'x#' -o -z ${COUNT:0:1} ]; then
		    continue
		fi
		getmodemname $TYPE $MODEMID
		if [ $IO = 0 -o $IRQ = 0 ]; then
			log -en ${CFILEERR}${MODEMNAME}":io=${IO}, irq=$IRQ"
			log $CFILEMISSINGENTRY
			if [ $ALLSILENT != 'y' ]; then	
			    echo -e ${WINMODEMINFO}${FAILED}
			fi
			continue
		fi
		querysetserial ${DEVICENO} ${IO} ${IRQ} ${MODEMID} \
				${TYPE} ${MODEMNAME}
		if [ $? -eq 0 ]; then
		    DEVICENO=${DEVICENO}+1
		fi
	done
}


function dotestdev()
{
    dev=$1
    stime=$2
    tfile=$3
    log -n ${stime}$SLEEPINGMSG1
    #read dummy <&1
    sleep $stime
    log -n $TESTMSG
    echo -e at\n > $dev | cat $dev > ${tfile} &
    testpid=$!
    sleep 2
    kill -9 $testpid &>/dev/null
    if [ -s ${tfile} ]; then
	log $DONE
	return 0
    fi
    log $FAILED
    return 1
}

function testddev()
{
    DEV=$1
    log ${DEVTEST}${DEV}
    declare -i i=1
    while [ $i -lt 4 ]; do
	let n=$i*2
	dotestdev $DEV $n ${TMPFILE2}
	RES=$?
	if [ $RES = 0 ]; then
	    #log $MODEMRESPONSE
	    choise=$YASTCHOICE0
	    if [ -f /usr/bin/wvdial.lxdialog ]; then
		choise=${choise}${YASTCHOICE1}
	    fi
	    ps ax | grep "X :" &>/dev/null
	    if [ $? -eq 0 ]; then
		XRUN='y'
	    else
		XRUN='n'
	    fi
	    if [ -f /bin/yast2 -a $XRUN = 'y' ]; then
		choise=${choise}${YASTCHOICE2}
	    fi
	    if [ $ALLSILENT != 'y' ]; then
		log -n ${YASTCHOICE3}${choise}${YASTCHOICE4}
		read repl <&1
		log -s "reply=$repl"
	    fi
	    test ! -z ${repl##* } || repl=0
	    case ${repl} in
		1)
		   if [ $XRUN = 'y' ]; then
			xterm -e "/usr/bin/wvdial.lxdialog" 
		   else
			/usr/bin/wvdial.lxdialog <&1
		   fi
		   log ${DEVTEST}${DEV}"..."$DONE
 		   return 0
		   ;;
		2)
		   if [ $XRUN = 'y' ]; then
			/bin/yast2 &
			pid=$!
			while [ $RES = 0 ]; do
			    sleep 1
			    kill -17 $pid
			    RES=$?
			done
			log ${DEVTEST}${DEV}$DONE
			return 0
		   else
			log $YASTERR1
			log $FAILED
			return -1
		   fi
		   ;;
		*)
		   log $ABORT
		   return 0
		   ;;
	    esac
	    return 0
	fi
	i=$i+1
    done

    log ${DEVTEST}${DEV}$FAILED

    return 1
}

function unsetmyserials()
{
    if [ -f $FSERIAL ]; then
	eval `cat $FSERIAL | \
	sed -n ':t;/'"${FSERAILHEAD}"'/bx;n;bt;:x;n;s/irq.*$/irq 0 port 0 uart unknown/p;bt;'`
	log -s -n "reset modem kerana modem sudah "
	log -s "dikonfigurasi oleh skrip ini"
	cat $FSERIAL | \
	sed -n ':t;/'"${FSERAILHEAD}"'/bx;p;n;bt;:x;n;n;bt;' > ${TMPFILE3}
	mv ${TMPFILE3} ${FSERIAL}
	log -s "buang setting di ${FSERIAL}"
    fi
}

function writetoserial()
{
    SERIALCMD=$1
    SERCHEC=$1
    log -n $FSERIALMSG
    if [ ! -w ${FSERIAL} ]; then
	log ${FSERIALERR1}${FSERIAL}${FSERIALERR}${SERIALCMD}${FSERIALERR3}
	return 1
    fi
    TOFSERIAL2="    ${SERIALCMD}"
    cat $FSERIAL | \
    sed  ':t;/AUTOMATIC CONFIGURATION/bx;n;bt;:x;n;n;n;n;n;a\
'"${FSERAILHEAD}"' \
'"${TOFSERIAL2}" > ${TMPFILE3}
    if [ $? -eq 0 -a -s ${FSERIAL} ]; then
	mv ${TMPFILE3} ${FSERIAL}
	log -s "added\n  ${SERIALCMD}\nto the file ${FSERIAL}"
    else
	log "perlu untuk jalankan arahan\n${SERIALCMD}"
	log "setiap kali boot sistem"
    	log $FAILED
	return 1
    fi
    log $DONE
    log -s "konfigurasi akan sentiasa dimulakan waktu boot"
}


# utama

if [ ! -x /sbin/lspci ]; then #bergantung kepada konfigurasi komputer
    echo "'lspci' tidak dijumpai'"
    echo "sila pasang pakej 'pciutils'"
    exit 1
fi

if [ ! -x /sbin/isapnp -o ! -x /sbin/pnpdump ]; then #bergantung kepada konfigurasi komputer
    echo "'isapnp' atau 'pnpdump' tidak dijumpai'"
    echo "sila pasang 'isapnp'"
    exit 1
fi

if [ ! -x /bin/setserial ]; then #bergantung kepada konfigurasi komputer
    echo "'setserial' tidak dijumpai'"
    echo "sila pasang pakej 'util'"
    exit 1
fi

case $1 in
  -s)
    ALLSILENT='y'
    ;;
  -h|--help|-?)
	printhelp
	exit 0
    ;;
  *)
    ;;
esac

if [ $ALLSILENT != 'y' ]; then
   echo -ne "Language/Bahasa? (1=english,2=melayu): "
   read repl <&1
   log -s "reply=$repl"
fi
case $repl in
    2) LANG=my ;;
    # sebelum nie 2) LANG=de
    *) LANG=en ;;
esac
LNAME="${0}.$LANG"
if [ ! -f $LNAME ]; then
    echo cannot find file $LNAME. Exit
    exit 1
fi
. $LNAME

if [ $ALLSILENT = 'y' ]; then	
    DONE=$SDONE
    FAILED=$SFAILED
    ABORT=$SABORT
fi

if [ $UID -ne 0 ]; then
    echo $ROOTMSG
    exit 1
fi

touch ${FRUN}
if [ $? -ne 0 ]; then
    log "Tidak dapat melaksanakan arahan..."
fi

touch ${FLOG}
if [ $? -ne 0 ]; then
    log "Tidak dapat membuat fail log..."
fi

TMPFILE1=`mktemp -q /tmp/$base.XXXXXX`
if [ $? -ne 0 ]; then
	log  "Tidak dapat buat fail sementara..."
	exit 1
fi
echo "# pnp dijumpai" > $TMPFILE1
echo "# format:" >> $TMPFILE1
echo "# no${SEP}type${SEP}id${SEP}irq${SEP}io${SEP}ok" >> $TMPFILE1

TMPFILE2=`mktemp -q /tmp/$base.XXXXXX`
if [ $? -ne 0 ]; then
    log "Tidak dapat buat fail sementara..."
    exit 1
fi
if [ -f $FLOG ]; then
    rm -f $FLOG
fi

TMPFILE3=`mktemp -q /tmp/$base.XXXXXX`
if [ $? -ne 0 ]; then
    log -s "Tidak dapat buat fail sementara"
    log $FAILED
    exit 1
fi

TMPFILE4=`mktemp -q /tmp/$base.XXXXXX`
if [ $? -ne 0 ]; then
   log "Tidak dapat buat fail sementara..."
   exit 1
fi


getallpcidata
getallisadata
setserialall
cleanup
