#! /bin/bash # $Id: faxaddmodem.sh.in,v 1.6 2006/06/02 18:57:58 faxguy Exp $ # # Warning, this file was automatically created by the HylaFAX configure script # # HylaFAX Facsimile Software # # Copyright (c) 1990-1996 Sam Leffler # Copyright (c) 1991-1996 Silicon Graphics, Inc. # HylaFAX is a trademark of Silicon Graphics # # Permission to use, copy, modify, distribute, and sell this software and # its documentation for any purpose is hereby granted without fee, provided # that (i) the above copyright notices and this permission notice appear in # all copies of the software and related documentation, and (ii) the names of # Sam Leffler and Silicon Graphics may not be used in any advertising or # publicity relating to the software without the specific, prior written # permission of Sam Leffler and Silicon Graphics. # # THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, # EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY # WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. # # IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR # ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, # OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, # WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF # LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE # OF THIS SOFTWARE. # # # VERSION: 4.3.0.4 # DATE: Sun Jun 18 10:31:45 CEST 2006 # TARGET: i686-pc-linux-gnu # # # faxaddmodem [tty] # # This script interactively configures a HylaFAX server # from keyboard input on a standard terminal. There may # be some system dependencies in here; hard to say with # this mountain of shell code! # SPOOL=/var/spool/hylafax INTERACTIVE=yes SKELFILE= SPEED= while [ x"$1" != x"" ] ; do case $1 in -s) SPEED=$2; shift;; -nointeractive) INTERACTIVE=no;; -skel=*) SKELFILE="`echo $1 | sed 's/^-skel=//'`";; -*) echo "Usage: $0 [-s SPEED] [-nointeractive] [-skel=proto_file] [ttyname]"; exit 1;; *) TTY=$1;; esac shift done # Test selected modem speed against a list of known standards if [ "$SPEED" != "" ] && [ "$SPEED" != 38400 ] && [ "$SPEED" != 19200 ] \ && [ "$SPEED" != 9600 ] && [ "$SPEED" != 4800 ] && [ "$SPEED" != 2400 ] \ && [ "$SPEED" != 1200 ]; then cat</dev/null` test -z "$euid" && test -w /dev && euid=root if [ "$euid" != "root" ]; then echo "Sorry, but you must run this script as the super-user!" exit 1 fi # security TMPDIR=`(mktemp -d /tmp/.faxaddmodem.XXXXXX) 2>/dev/null` if test X$TMPDIR = X; then TMPDIR=/tmp/.faxaddmodem$$ fi /bin/rm -rf $TMPDIR (umask 077 ; mkdir $TMPDIR) || exit 1 SH=$SCRIPT_SH # shell for use below CPATH=$SPOOL/etc/config # prefix of configuration file OUT=$TMPDIR/faxaddmodem.sh$$ # temp file in which modem output is recorded SVR4UULCKN=$LIBEXEC/lockname # SVR4 UUCP lock name construction program ONDELAY=$LIBEXEC/ondelay # prgm to open devices blocking on carrier CAT="$CAT -u" # something to do unbuffered reads and writes FAX=fax # identity of the fax user GROUP=/etc/group # where to go for group entries PROTOGID=uucp # group who's gid we use for FAX user defPROTOGID=10 # use this gid if PROTOGID doesn't exist MODEMCONFIG=$SPOOL/config # location of prototype modem config files RMCMD="$RM -f" # forced removal # # Build a list of config files in a portable way for grepping... # cd $MODEMCONFIG CONFIG_LIST="" for file in *; do if [ -f "$file" ]; then CONFIG_LIST="$CONFIG_LIST $file" fi done # # Prompt the user for a string that can not be null. # promptForNonNullStringParameter() { x="" while [ -z "$x" ]; do prompt "$2 [$1]?"; if [ "$INTERACTIVE" != "no" ]; then read x else echo x= fi if [ "$x" ]; then # strip leading and trailing white space x=`echo "$x" | $SED -e 's/^[ ]*//' -e 's/[ ]*$//'` else x="$1" fi done param="$x" } # # Prompt the user for a string that can be null. # promptForStringParameter() { prompt "$2 [$1]?"; if [ "$INTERACTIVE" != "no" ]; then read x else echo x= fi if [ "$x" ]; then # strip leading and trailing white space x=`echo "$x" | $SED -e 's/^[ ]*//' -e 's/[ ]*$//'` else x="$1" fi param="$x" } # # Prompt the user for a numeric value. # promptForNumericParameter() { x="" while [ -z "$x" ]; do prompt "$2 [$1]?"; if [ "$INTERACTIVE" != "no" ]; then read x else echo x= fi if [ "$x" ]; then # strip leading and trailing white space x=`echo "$x" | $SED -e 's/^[ ]*//' -e 's/[ ]*$//'` match=`expr "$x" : "\([0-9]*\)"` if [ "$match" != "$x" ]; then echo "" echo "This must be entirely numeric; please correct it." echo "" x=""; fi else x="$1" fi done param="$x" } # # Prompt the user for a C-style numeric value. # promptForCStyleNumericParameter() { x="" while [ -z "$x" ]; do prompt "$2 [$1]?"; if [ "$INTERACTIVE" != "no" ]; then read x else echo x= fi if [ "$x" ]; then # strip leading and trailing white space and C-style 0x prefix x=`echo "$x" | $SED -e 's/^[ ]*//' -e 's/[ ]*$//'` match=`expr "$x" : "\([0-9]*\)" \| "$x" : "\(0x[0-9a-fA-F]*\)"` if [ "$match" != "$x" ]; then echo "" echo "This must be entirely numeric; please correct it." echo "" x=""; fi else x="$1" fi done param="$x" } # # Prompt the user for a boolean value. # promptForBooleanParameter() { x="" while [ -z "$x" ]; do prompt "$2 [$1]?"; if [ "$INTERACTIVE" != "no" ]; then read x else echo x= fi if [ "$x" ]; then # strip leading and trailing white space x=`echo "$x" | $SED -e 's/^[ ]*//' -e 's/[ ]*$//'` case "$x" in n|no|off) x=no;; y|yes|on) x=yes;; *) cat <&2 if [ "$INTERACTIVE" = "no" ]; then exit 1; fi prompt "Serial port that modem is connected to [$TTY]?"; read TTY done JUNK="$OUT" trap "$RMCMD \$JUNK; $RMCMD -r $TMPDIR; exit 1" 1 2 15 if [ ! -d $UUCP_LOCKDIR ]; then cat< $x done # zap any gettys or other users if ! [ -f $FUSER ]; then cat</dev/null 2>&1 fi cat< Spaces, hyphens, and periods can be included for legibility. For example, +$CountryCode.$AreaCode.555.1212 is a possible phone number (using your country and area codes). EOF ok=no; fi } # # Verify that a number is octal and if not, add a prefixing "0". # checkOctalNumber() { param=$1 if [ "`expr "$param" : '\(.\)'`" != 0 ]; then param="0${param}" return 0 else return 1 fi } checkForLocalFile() { f="`echo $1 | $SED 's/\"//g'`" if [ ! -f $SPOOL/$f ]; then cat<$PROMPTS</dev/null 2>&1;; cua*) ttysoftcar -n $TTY >/dev/null 2>&1;; esac ;; esac if [ -x ${ONDELAY} ]; then onDev() { if [ "$1" = -c ]; then shift; catpid=`${ONDELAY} $tdev $SH -c "$* >$OUT" & echo $!` else ${ONDELAY} $tdev $SH -c "$*" fi } else cat<<'EOF' The "ondelay" program to open the device without blocking is not present. We're going to try to continue without it; let's hope that the serial port won't block waiting for carrier... EOF onDev() { if [ "$1" = -c ]; then shift; catpid=`$SH <$tdev >$tdev -c "$* >$OUT" & echo $!` else $SH <$tdev >$tdev -c "$*" fi } fi STTY=`ttyStty $tdev` # appropriate stty cmd # # Send each command in SendString to the modem and collect # the result in $OUT. Read this very carefully. It's got # a lot of magic in it! # SendToModem() { COMMAND=$* sleep 1 # wait for previous kill case $TARGET in *-linux*) ;; *) onDev $STTY 0; sleep 1 ;; # reset the modem (hopefully) esac # start listening for output onDev -c "$STTY clocal && exec $CAT $tdev"; sleep 2 # # NB: eof is set to ^A so that only 1 character is needed # for a pending read on HPUX systems # onDev $STTY -echo -icrnl -ixon -ixoff -isig eof '"^A"' clocal $SPEED; sleep 1 # NB: merging \r & ATQ0 causes some modems problems printf "\r" >$tdev; sleep 1; # force consistent state printf "ATQ0V1E1\r" >$tdev; sleep 1; # enable echo and result codes for i in $COMMAND; do printf "$i\r" >$tdev; sleep 1; done kill -9 $catpid; catpid= # NB: [*&\\\\$] must have the "$" last for AIX (yech) pat=`echo "$i"|$SED -e 's/[*&\\\\$]/\\\\&/g'` # escape regex metacharacters RESPONSE=`tr -ds '\015' '\012' < $OUT | \ $SED -n "/$pat/{n;s/ *$//;p;q;}" | $SED 's/+F.*=//'` } echo "" if [ -z "$SPEED" ]; then # # Probe for the highest speed at which the modem # responds to "AT" with "OK". # printf "Probing for best speed to talk to modem:" SPEEDS=`ttySpeeds $tdev` # set of speeds for auto-bauding for SPEED in $SPEEDS do printf " $SPEED" SendToModem AT >/dev/null 2>&1 sleep 1 RESULT=`tr -ds '\015' '\012' < $OUT | $SED -n '$p'` test "$RESULT" = OK && break; done if [ "$RESULT" != OK ]; then echo "" echo "Unable to deduce DTE-DCE speed; check that you are using the" echo "correct device and/or that your modem is setup properly. If" echo "all else fails, try the -s option to lock the speed." exit 1 fi echo " OK." else echo "Using user-specified $SPEED to talk to modem." fi RESULT=""; while [ -z "$RESULT" ]; do # # This goes in the background while we try to # reset the modem. If something goes wrong, it'll # nag the user to check on the problem. # (trap "exit 1" 1 2 15; while true; do sleep 10; echo "" echo "Hmm, something seems to be hung, check your modem eh?" done)& nagpid=$! trap "$RMCMD \$JUNK; $RMCMD -r $TMPDIR; kill $nagpid \$catpid; exit 1" 1 2 15 SendToModem "AT+FCLASS=?" # ask for class support exec 3>&2 2> /dev/null # Mute stderr against child death kill $nagpid wait $nagpid # Really waits its end exec 2>&3 3>&- # Restore stderr trap "$RMCMD \$JUNK; $RMCMD -r $TMPDIR; test \"\$catpid\" && kill \$catpid; exit 1" 1 2 15 sleep 1 RESULT=`tr -ds '\015' '\012' < $OUT | $SED -n '$p'` if [ -z "$RESPONSE" ]; then echo "" echo "There was no response from the modem. Perhaps the modem is" echo "turned off or the cable between the modem and host is not" echo "connected. Please check the modem and hit a carriage return" prompt "when you are ready to try again:" read x fi done ModemType="" Manufacturer="" Model="" ProtoType=skel # # Initialize desired flow control scheme # according to the device name (if it's # meaningful). Otherwise, setup to use any # default flow control defined in the prototype # configuration file. # FlowControl=default case $TARGET in *-irix*) case $TTY in ttym${PORT}) FlowControl=xonxoff;; ttyf${PORT}) FlowControl=rtscts;; esac ;; esac # # Prompt the user for a flow control scheme. # promptForFlowControlParameter() { x="" while [ -z "$x" ]; do prompt "$2 [$1]?"; if [ "$INTERACTIVE" != "no" ]; then read x else echo x= fi if [ "$x" ]; then # strip leading and trailing white space x=`echo "$x" | $SED -e 's/^[ ]*//' -e 's/[ ]*$//'` case "$x" in xon*|XON*) x=xonxoff;; rts*|RTS*) x=rtscts;; def*|DEF*) x=default;; *) cat <$PROMPTS . $PROMPTS fi printModemConfig case $TARGET in *-irix*) checkFlowControlAgainstTTY;; esac # # XXX not sure what kind of consistency checking that can # be done w/o knowing more about the modem... # prompt "Are these ok [yes]?"; if [ "$INTERACTIVE" != "no" ]; then read ok else echo ok= fi done TMPSED=$TMPDIR/faxsed$$; JUNK="$JUNK $TMPSED" (echoServerSedCommands; echoModemSedCommands)>$TMPSED # # All done with the prompting; edit up a config file! # echo "" echo "Creating new configuration file $CONFIG..." JUNK="$JUNK $CONFIG.new" if $SED -f $TMPSED $proto >$CONFIG.new; then if cmp -s $CONFIG.new $CONFIG >/dev/null 2>&1; then echo "...nothing appears to have changed; leaving the original file." $RMCMD $CONFIG.new else if [ -f $CONFIG ]; then echo "...saving current file as $CONFIG.sav." mv $CONFIG $CONFIG.sav fi $MV $CONFIG.new $CONFIG $CHOWN $FAX $CONFIG $CHGRP $faxGID $CONFIG $CHMOD 644 $CONFIG fi else echo "" echo "*** Sorry, something went wrong building $CONFIG.new." echo "*** The original config file is unchanged; I'm terminating before" echo "*** I do something stupid." echo "" exit 1 fi # # Create FIFO. special file and remove any old one. # FIFO=$SPOOL/FIFO.$DEVID test -p $FIFO || { prompt "Creating fifo $FIFO for faxgetty..." if (mkfifo $FIFO) >/dev/null 2>&1; then echo "done." elif (mknod $FIFO p) >/dev/null 2>&1; then echo "done." else echo "" echo "*** Unable to create fifo \"$FIFO\"; terminating." exit 1 fi } $CHOWN $FAX $FIFO; $CHGRP $faxGID $FIFO; $CHMOD 600 $FIFO if [ "$OLDFIFO" ]; then echo "Removing old fifo $OLDFIFO."; $RMCMD $OLDFIFO; fi echo "Done setting up the modem configuration." echo "" # # Configuration parameters specific to scheduler operation. # Required parameters are *always* emitted in the created # configuration file; optional parameters are emitted # only if the configured value differs from the default # value known to be used by the server. # # NB: the order of some parameters is important; e.g. # DialStringRules must be after AreaCode and CountryCode. # RequiredSchedulerParameters=" LogFacility CountryCode AreaCode LongDistancePrefix InternationalPrefix DialStringRules ServerTracing " OptionalSchedulerParameters=" ContCoverPage ContCoverCmd DestControls MaxConcurrentCalls MaxDials MaxSendPages MaxTries ModemGroup PostScriptTimeout PS2FaxCmd SendFaxCmd SendPageCmd SendUUCPCmd SessionTracing TimeOfDay Use2D " defaultContCoverPage= defaultContCoverCmd=\"bin/mkcover\" defaultDestControls= defaultMaxConcurrentCalls=1 defaultMaxDials=12 defaultMaxSendPages=0xffffffff defaultMaxTries=3 defaultModemGroup= defaultPostScriptTimeout=180 defaultPS2FaxCmd=\"bin/ps2fax\" defaultSendFaxCmd=\"bin/faxsend\" defaultSendPageCmd=\"bin/pagesend\" defaultSendUUCPCmd=\"bin/uucpsend\" defaultSessionTracing=0xffffffff defaultTimeOfDay=\"Any\" defaultUse2D=Yes # # NB: these defaults are set above # OptionalParameters=" $OptionalSchedulerParameters JobReqOther NotifyCmd UUCPLockDir UUCPLockTimeout UUCPLockType " SchedulerParameters=" $RequiredSchedulerParameters $OptionalParameters " # # The following parameters are checked to make sure # they have values consistent with what was just written # to the modem configuration file. It is ok for some # of these to be different, but usually they should be # the same so if they disagree we prompt the user to # see if we should propagate the new values from the # modem config file to the scheduler config file. # CheckedParameters=" LogFacility CountryCode AreaCode LongDistancePrefix InternationalPrefix DialStringRules JobReqOther NotifyCmd UUCPLockDir UUCPLockTimeout UUCPLockType " # # Echo the configuration lines for those scheduler parameters # whose value is different from the default value. Note # that we handle the case where there is embedded whitespace # by enclosing the parameter value in quotes. # echoSchedulerParameters() { (for i in $RequiredSchedulerParameters; do eval echo \"$i:\$$i:\" done for i in $OptionalSchedulerParameters; do eval echo \"$i:\$$i:\$default$i\" done) | $AWK -F: ' function p(tag, value) { tabs = substr("\t\t\t", 1, 3-int((length(tag)+1)/8)); if (match(value, "^[^\"].*[ ]") == 0) printf "%s:%s%s\n", tag, tabs, value else printf "%s:%s\"%s\"\n", tag, tabs, value } $2 != $3{ p($1, $2) }' } # # Print the current server configuration parameters. # printSchedulerConfig() { (for i in $SchedulerParameters; do eval echo \"$i:\$$i:\$default$i\" done) | $AWK -F: ' function p(tag, value) { tabs = substr("\t\t\t", 1, 3-int((length(tag)+1)/8)); printf "%s:%s%s\n", tag, tabs, value } BEGIN { printf "\nThe non-default scheduler parameters are:\n\n" } $2 != $3{ p($1, $2) } END { printf "\n" }' } # # Check the current contents of the scheduler configuration file # against that parameters just setup for the per-modem config file. # If anything has changed (e.g. phone number info), then prompt # the user to update the file. # updateConfig=yes # # Initialize server parameters from the defaults. # for i in $OptionalSchedulerParameters; do eval $i=\$default$i done if [ -f $SCHEDCONFIG ]; then echo "Checking $SCHEDCONFIG for consistency..." # # Save current settings in variables with a ``modem'' prefix. # for i in $CheckedParameters; do eval modem$i=\$$i done # # Read old configuration file in as the ``current settings''. # getServerParameters $SCHEDCONFIG # # Check current parameter settings against ``modem settings''. # If inconsistencies are detected in the parameters that should # (by default) be kept consistent, then try to propagate the new # parameter settings from the modem config file to the scheduler # config file. # ok=yes for i in $CheckedParameters; do eval test \"\$$i\" != \"\$modem$i\" && { ok=skip; break; } done if [ $ok != yes ]; then echo "...some parameters are different." # # Move the ``modem settings'' to the current settings # and let the user ok them or change them to what they # want. We do this shuffle w/o touching the default # settings so that optional parameter handling works # (i.e. that only non-default values for optional params # are displayed and/or written to the file). # for i in $CheckedParameters; do eval $i=\$modem$i done else echo "...everything looks ok; leaving existing file unchanged." updateConfig=no fi else echo "No scheduler configuration file exists, creating one from scratch." ok=skip # got important params above fi rm -f $PROMPTS while isNotOK $ok; do if [ "$ok" != skip ]; then test -f $PROMPTS || compilePrompts>$PROMPTS<$SCHEDCONFIG.new 2>/dev/null if cmp -s $SCHEDCONFIG.new $SCHEDCONFIG >/dev/null 2>&1; then echo "...nothing appears to have changed; leaving the original file." rm -f $SCHEDCONFIG.new elif [ -s $SCHEDCONFIG.new ]; then if [ -f $SCHEDCONFIG ]; then echo "...saving current file as $SCHEDCONFIG.sav." $MV $SCHEDCONFIG $SCHEDCONFIG.sav fi $MV $SCHEDCONFIG.new $SCHEDCONFIG $CHOWN $FAX $SCHEDCONFIG $CHGRP $faxGID $SCHEDCONFIG $CHMOD 644 $SCHEDCONFIG else echo "" echo "*** Sorry, something went wrong building $SCHEDCONFIG.new." echo "*** The original config file is unchanged; check your disk space?" echo "" exit 1 fi fi echo "" echo "Don't forget to run faxmodem(8C) (if you have a send-only environment)" echo "or configure init to run faxgetty on $TTY." exec >/dev/null 2>&1 # cleanup $RMCMD $JUNK; $RMCMD -r $TMPDIR exit 0