#!/bin/sh # # faxspool - sample script how to spool fax input data to a spool # directory, creating jobs to be run by faxrunq # # sccsid: @(#)faxspool.in 4.2 97/03/18 (c) Gert Doering # # syntax: faxspool [flags] # # may be any number of files. The file type has to be guessed - # for now, the following file extensions are recognized: # # .ps -> PostScript # .t -> plain ascii text # .dvi -> TeX device independent output file (use dvips, then like .ps) # .pbm -> PortableBitMap (use pbm2g3) # .pgm -> PortableGrayMap (use pgmtopbm | pbm2g3) # .ppm -> PortablePixMap (use ppmtopgm | pgmtopbm | pbm2g3) # .g3 -> raw G3 fax data # .lj -> HP Laserjet PCL4 (use hp2pbm) # .xwd -> xwindow-dump (by xwd program, use xwdtopnm) # # ChangeLog: # 3.6.93: use dvips instead of dvialw now (GD) # 15.9.93: use g3cat to concatenate header and page (GD) # 3.10.93: use "hp2hig3" for hp-pcl4-files (cl) # 19.10.93: phone directories (caz) FAX_SPOOL=/var/spool/fax FAX_SPOOL_OUT=/var/spool/fax/outgoing FAX_SEQ=$FAX_SPOOL_OUT/.Sequence FAX_SEQ_LOCKDIR=$FAX_SPOOL_OUT/locks FAX_SEQ_LOCK=$FAX_SEQ_LOCKDIR/LCK..seq # fax phone directories - format: GLOBAL_PHONE_DIR=/etc/mgetty+sendfax/faxaliases PRIVATE_PHONE_DIR=$HOME/.faxnrs # permissions - see the "crontab" or "faxspool" manual page for a # description how the files have to be set up # FAX_ALLOW=/etc/mgetty+sendfax/fax.allow FAX_DENY=/etc/mgetty+sendfax/fax.deny # you have to adapt this to your local system! # # this is the file with the fax header - @T@ / @P@ / @M@ / @U@ stand for # telephone / page number / maximum page number / user name, respectively FAX_HEADER=/etc/mgetty+sendfax/faxheader # # for creating the fax page header, pbmtext is used, and this specifies # the font file to use (fine/normal res.) PBMFONT_HEADER_F=/usr/lib/mgetty+sendfax/cour25.pbm PBMFONT_HEADER_N=/usr/lib/mgetty+sendfax/cour25n.pbm # # if you want to use pbmtext for converting ASCII texts, use these fonts: PBMFONT_BODY_F=/usr/lib/mgetty+sendfax/cour25.pbm PBMFONT_BODY_N=/usr/lib/mgetty+sendfax/cour25n.pbm # # these are the drivers used in Ghostscript - choose dfaxhig/low or faxg3 GS_DRIVER_HI="-sDEVICE=dfaxhigh" GS_DRIVER_LO="-sDEVICE=dfaxlow" #GS_DRIVER_HI="-sDEVICE=faxg3 -r204x196" #GS_DRIVER_LO="-sDEVICE=faxg3 -r204x98" # # program that will generate fax coverpage (see "man coverpg") # MAKE_COVER_PG=/usr/lib/mgetty+sendfax/make.coverpg # # local fax number (will be overriden by "sendfax.config" if set there!) # FAX_STATION_ID="49 89 xxxxxxxx" # # echo program that will accept escapes (bash: "echo -e", sun: /usr/5bin/echo) # echo="echo" AWK=awk # # make sure that pbm2g3 and newslock can be found # PATH=/usr/bin:$PATH #### end of configuration section # #### shell functions for conversions # # naming scheme: fs_cvt_$type() # converts a $type file ($1) to g3 file(s), named $2.$i, where "i" # should be the page number. Can be omitted if $1 has only one page. # $3 can be a flag argument, "-n" for normal resolution # # convert portable bitmap (not scaled) - see pbm(5), pbm2g3(1) # fs_cvt_pbm() { pbm2g3 $1 >$2.001 } # # convert portable greymap (not scaled) - see pgm(5) # fs_cvt_pgm() { pgmtopbm $1 | pbm2g3 >$2.001 } # # convert portable pixmap (no scaling) - see ppm(5) # fs_cvt_ppm() { ppmtopgm $1 | pgmtopbm | pbm2g3 >$2.001 } # # "convert" G3 file # actually, it's just copied, but I want the interface to be the same # later on, one could do page resizing, resolution changing, ... here # fs_cvt_g3() { g3cat $1 >$2.001 } # # convert a X11 xwd file - scaled to fill the whole page width # since we do not know whether it's colour or grey or what, we have # to do *all* the conversions *all* the time - ugly. FIXME. # fs_cvt_xwd() { REDUCE="cat" test X$3 = X-n && REDUCE="pnmscale -yscale 0.5" xwdtopnm $1 |\ pnmscale -xysize 1728 2000 |\ $REDUCE |\ ppmtopgm |\ pgmtopbm |\ pbm2g3 >$2.001 } # # convert a CompuServe GIF file, also properly scaled # problem: a GIF file can contain multiple images - FIXME # fs_cvt_gif() { REDUCE="cat" test X$3 = X-n && REDUCE="pnmscale -yscale 0.5" giftoppm $1 |\ pnmscale -xysize 1728 2000 |\ $REDUCE |\ ppmtopgm |\ pgmtopbm |\ pbm2g3 >$2.001 } # # convert TIFF file # problem1: conversion always via ppm, pgm # problem2: multipage TIFFs # fs_cvt_tif() { REDUCE="cat" test X$3 = X-n && REDUCE="pnmscale -yscale 0.5" tifftopnm $1 |\ pnmscale -xysize 1728 2000 |\ $REDUCE |\ ppmtopgm |\ pgmtopbm |\ pbm2g3 >$2.001 } # # convert HP laserjet input files # needs Chris Lewis' hp2pbm package (ftp.uunet.ca) # fs_cvt_lj() { if [ X$3 = X-n ] then hp2log3 -r$2 <$1 else hp2hig3 -r$2 <$1 fi } # # convert postscript data # needs GNU GhostScript installed. # For driver selection, see definition of GS_DRIVER_{HI,LO} above. # fs_cvt_ps() { driver="$GS_DRIVER_HI" test X$3 = X-n && driver="$GS_DRIVER_LO" cat $1 | gs $driver -sOutputFile=$2%03d -dNOPAUSE -q -dSAFER - } # # convert ASCII text files # go via GhostScript and gslp.ps # (could also used hp2hig3 or nenscript -> gs or pbmtext) # fs_cvt_ascii() { ##### # via Ghostscript: driver="$GS_DRIVER_HI" test X$3 = X-n && driver="$GS_DRIVER_LO" gs $driver -sOutputFile=$2%03d -dNOPAUSE \ -- gslp.ps -fCourier-Bold10 -B $1 ##### # via hp2pbm: # (convert "LF" to "CR+LF" via awk) # pgm=hp2hig3 # test X$3 = X-n && pgm=hp2log3 # # $AWK '{ printf "%s\r\n", $0 }' $1 | $pgm -r$2 ##### # via pbmtext (not really recommended): # use the "pgx" program in contrib/ to split pages ## Select appropriate font # font=$PBMFONT_BODY_F # test X$3 = X-n && font=$PBMFONT_BODY_N # Determine how many pages text will be split in to. Uses default pagelen. # nr=`pgx < $1` # Convert each page into a separate G3 file. Uses default pagelen (60). # page=1 # while [ $page -le $nr ]; do # pgx $page < $1 | pbmtext -font $font | pbm2g3 >$2.$page # page=`expr $page + 1` # done } # # convert TeX DVI files # needs GhostScript and dvips installed. # alternatively, one could use dvialw. # fs_cvt_dvi() { if [ X$3 = X-n ] then driver="$GS_DRIVER_LO" ; dvipscfg="-P dfaxlo" else driver="$GS_DRIVER_HI" ; dvipscfg="-P dfaxhigh" fi # if you do not have the dfaxlo(w)/dfaxhigh dvips modes configured, # remove "$dvipscfg" from the dvips command line below [or configure them!] dvips $dvipscfg $1 -o \ !"gs $driver -sOutputFile=$2%03d -dNOPAUSE -dSAFER -q -" # for those that only have the old "dvialw": # # dvialw <$file | # gs $driver -sOutputFile=$2%03d -dNOPAUSE -dSAFER -q - # for those that have dvi2ps and not dvips: # # dvi2ps -r -q $q | # gs $driver -sOutputFile=$2%03d -dNOPAUSE -dSAFER -q - } # #### "main" function # # # setup defaults / get values # # user name (for authentification) ########## if user=`logname 2>/dev/null` then : else id=`id` user=`expr "$id" : "[^( ]*(\([^)]*\)"` fi test -z "$user" && user=$LOGNAME test -z "$user" && user=$USER if [ -z "$user" ] then $echo "cannot determine user id. fix program." >&2 exit 1 fi # email (for return mail) ########## test -z "$USER" && USER=$LOGNAME test -z "$USER" && USER=$user # fax ID (from sendfax.config) ########## eval ` $AWK '$1=="fax-id" { printf "FAX_STATION_ID=\"%s", $2; \ for(i=3;i<=NF;i++) printf " %s", $i; print "\""; } $1=="port" { exit }' /etc/mgetty+sendfax/sendfax.config 2>/dev/null` # everything else is initialized empty ########## poll_req="" verbose_to="" normal_res="" TIME="" copy_source="" # # get command line arguments (overriding some of the values above) ########## # usage="Usage: $0 [options] [faxphone] [page data] Options: \t-p\t\tpoll request \t-n\t\tnormal resolution \t-C \tset cover page program (\"-\" for none) \t-D \tset verbose destination name \t-F \tset full name of sender \t-h \ttext file for page header \t-f \tset address for status mail \t-c\t\tcopy source files \t-t \tset earliest possible send time \t-t set time range for sending fax \t-q\t\tshut up" while : do case "$1" in # enable polling -p) poll_req=true ; shift ;; # use normal resolution (as opposed to fine resolution) -n) normal_res="-n" ; shift ;; # set cover page program to use -C) case "$2" in '') $echo "$usage" >&2 ; exit 2 ;; "-") MAKE_COVER_PG="" ;; /*) MAKE_COVER_PG="$2" ;; *) MAKE_COVER_PG=`pwd`/"$2" ;; esac shift ; shift ;; # set verbose destination address -D) case "$2" in '') $echo "$usage" >&2 ; exit 2 ;; esac verbose_to="$2" shift ; shift ;; # set verbose origination address ("fullname") -F) case "$2" in '') $echo "$usage" >&2 ; exit 2 ;; esac FULLNAME="$2" shift ; shift ;; # set page header text file -h) case "$2" in '') $echo "$usage" >&2 ; exit 2 ;; '-') FAX_HEADER="" ;; /*) FAX_HEADER="$2" ;; *) FAX_HEADER=`pwd`/"$2" ;; esac test ! -z "$FAX_HEADER" && \ if [ ! -f "$FAX_HEADER" ] ; then $echo "$0: no such fax header file: '$2'" >&2 exit 2; fi shift ; shift ;; # set e-mail return address -f) case "$2" in '') $echo "$usage" >&2 ; exit 2 ;; esac USER="$2" shift ; shift ;; # set user name for authorization purposes (only allowed for ``trusted'' users -u) case "$2" in '') $echo "$usage" >&2 ; exit 2 ;; esac if [ "$user" = "root" -o "$user" = "fax" -o \ "$user" = "lp" -o "$user" = "daemon" ] then user="$2" else $echo "not authorized to use \`\`-u $2'' switch." >&2 exit 3 fi shift ; shift ;; # set first time to send fax -t) if expr "$2" : "[0-2][0-9]:[0-9][0-9]$" >/dev/null then h=`expr "$2" : "\(..\)"` m=`expr "$2" : "..:\(..\)"` if [ "$h" -gt 23 -o "$m" -gt 60 ] then $echo "Invalid time specified: $h:$m" >&2; exit 2 fi TIME="$h$m" else $echo "Time must be in format." >&2; exit 2 fi shift ; shift ;; # set accounting handle (just a string that will be logged) -A) case "$2" in '') $echo "$usage" >&2 ; exit 2 ;; esac ACCT_HANDLE="$2" ; shift ; shift ;; # shut up -q) exec >/dev/null ; shift ;; # copy source file (for "some action" when transmission fails) -c) copy_source=TRUE; shift ;; # unknown options -*) $echo "unknown option: $1" >&2 $echo "$usage" >&2 exit 1 ;; # anything else: leave loop *) break esac done # # if not yet set, get full name from /etc/passwd (name only) # if [ -z "$FULLNAME" ] then FULLNAME=`grep "^$user:" /etc/passwd | cut -f5 -d: | cut -f1 -d,` fi # # validate user # if [ -r $FAX_ALLOW ] then if cut -d" " -f1 $FAX_ALLOW | grep "^$user$" >/dev/null then : else $echo "Sorry $user, you are not allowed to use the fax service." >&2 exit 1 fi elif [ -r $FAX_DENY ] then if grep "^$user$" $FAX_DENY >/dev/null then $echo "Sorry $user, you are not allowed to use the fax service." >&2 exit 2 fi elif [ "$user" != "root" ] then $echo "Neither $FAX_ALLOW nor $FAX_DENY exist," >&2 $echo "so only root may use the fax service. Sorry." >&2 exit 2 fi # # check syntax # if [ $# -eq 0 ] ; then $echo "$0: phone number missing" >&2 $echo "$usage" >&2 exit 3 fi phone=$1 ; shift if expr "$phone" : "[-0-9TtPpW,;]*$" >/dev/null ; then : else alias="$phone" phone="" awkpgm='$1 == "'"$alias"'" { printf "phone=\"%s\"; vto=\"", $2; for ( i=3; i<=NF-1; i++ ) printf "%s ",$i; printf "%s\"\n", $i; exit }' if [ -r $PRIVATE_PHONE_DIR ] then eval `$AWK "$awkpgm" $PRIVATE_PHONE_DIR` fi if [ -z "$phone" -a -r $GLOBAL_PHONE_DIR ] then eval `$AWK "$awkpgm" $GLOBAL_PHONE_DIR` fi if [ -z "$phone" ] then $echo "$0:\nNon-numeric characters in phone number and" >&2 $echo "'$alias' not found in fax directories\n$usage" >&2 exit 4 fi [ -z "$verbose_to" ] && verbose_to="$vto" [ -z "$verbose_to" ] && verbose_to="$alias" $echo "sending fax to '$verbose_to' using phone number '$phone'..." fi # # check, if all the files exist & are readable # for file do if [ ! -r $file -a x$file != x- ] then $echo "$0: cannot open '$file'!" >&2 ; exit 5 fi done # # if no file specified on command line, use stdin # (only if not polling and no cover page) # if [ $# -eq 0 -a -z "$poll_req" -a -z "$MAKE_COVER_PG" ] then # if stdin is connected to a tty, notify user # tty -s && \ $echo "spooling text from standard input. End typing with ^D" >&2 set -- - fi # # check spool directory permissions # if [ ! -d $FAX_SPOOL_OUT ] ; then if mkdir $FAX_SPOOL_OUT ; then : else $echo "cannot create $FAX_SPOOL_OUT" >&2 ; exit 6 fi chmod 1777 $FAX_SPOOL_OUT chgrp 0 $FAX_SPOOL_OUT 2>/dev/null chown 0 $FAX_SPOOL_OUT 2>/dev/null fi if [ ! -w $FAX_SPOOL_OUT ] ; then $echo "cannot write to $FAX_SPOOL_OUT!" >&2 ; exit 6 ; fi # # get unique directory name (well, at least: try to) # FIXME: be smarter about already-existing directory names! # if [ ! -f $FAX_SEQ ] ; then $echo 000000 > $FAX_SEQ ; chmod 666 $FAX_SEQ ; fi if [ -f $FAX_SEQ -a ! -w $FAX_SEQ ] ; then $echo "cannot write to $FAX_SEQ!" >&2 ; exit 6 ; fi if [ ! -d $FAX_SEQ_LOCKDIR ] ; then if mkdir $FAX_SEQ_LOCKDIR ; then : else $echo "can't create $FAX_SEQ_LOCKDIR!" >&2 ; exit 6 ; fi chmod 777 $FAX_SEQ_LOCKDIR fi if newslock $FAX_SEQ $FAX_SEQ_LOCK ; then : else $echo "$0: sequence file locked, waiting 5 seconds..." sleep 5 if newslock $FAX_SEQ $FAX_SEQ_LOCK ; then : else $echo "$0: can't lock sequence number file. (Try again later)." exit 6 fi fi trap "rm -f $FAX_SEQ_LOCK" 0 1 2 3 15 new_seq=`$AWK '{ printf "%06d", $1 + 1 }' $FAX_SEQ` test -z "$new_seq" && new_seq="000800" echo $new_seq >$FAX_SEQ rm -f $FAX_SEQ_LOCK trap 0 1 2 3 15 spooldir=$FAX_SPOOL_OUT/F$new_seq if [ -d $spooldir ] ; then $echo "Ummm, strange - $spooldir exists (FIX THE SOURCE!)" >&2 ; exit 6 fi umask 022 if mkdir $spooldir ; then : else $echo "Cannot make $spooldir" >&2 ; exit 6 ; fi # # now: spool all the files to $spooldir # $echo "spooling to $spooldir..." # # process all input files # input_data="$*" F_NO=0001 for file do # # if filename is "-", use stdin # if [ x$file = x- ] then $echo "spooling $file (stdin)..." trap "rm /tmp/faxsp.$$" 0 cat - >/tmp/faxsp.$$ file=/tmp/faxsp.$$ else $echo "spooling $file..." fi format="" # # try to determine file type by extention (won't work for print spooler!) # case $file in *.g3) format="g3" ;; *.ps) format="ps" ;; *alw) format="ps" ;; *.dvi) format="dvi";; *.pbm) format="pbm";; *.pgm) format="pgm";; *.ppm) format="ppm";; *.t) format="ascii";; *.txt) format="ascii";; *.asc) format="ascii";; *.lj) format="lj" ;; *.pcl) format="lj" ;; *.xwd) format="xwd";; *.gif) format="gif";; *.tif) format="tif";; *.tiff) format="tif";; esac # if we don't know the file type now, let's try something more esoteric if [ -z "$format" ] then # # ask "file" # (extend /etc/magic if necessary!) # case "`LANG=C file $file | cut -d':' -f2- `" in *"nglish text"*) format="ascii" ;; *"ascii text"*) format="ascii" ;; *"ASCII text"*) format="ascii" ;; *"ews text"*) format="ascii" ;; *"ail text"*) format="ascii" ;; *"commands text"*) format="ascii" ;; *"c program text"*) format="ascii" ;; *"script text"*) format="ascii" ;; *PBM*) format="pbm" ;; *PGM*) format="pgm" ;; *PPM*) format="ppm" ;; *GIF*) format="gif" ;; *Digifax*) format="g3" ;; *DVI*) format="dvi" ;; *PCL*) format="lj" ;; *postscript*) format="ps" ;; *PostScript*) format="ps" ;; *TIF*) format="tif" ;; esac # if file told us, it's an ascii text, or if we still don't know, try # looking at the first few bytes (do not use "head", it may break on # binary data) if [ -z "$format" -o "$format" = "ascii" ] then case "`dd if=$file bs=1 count=4 2>/dev/null`" in %!*) format="ps" ;; P1*|P4*) format="pbm" ;; P2*|P5*) format="pgm" ;; P3*|P6*) format="ppm" ;; GIF*) format="gif" ;; # hmmm. II*) format="tif" ;; MM*) format="tif" ;; esac fi # # detect dvi by directly looking at bytes 16...25 # if [ -z "$format" ] then if [ "`dd if=$file bs=1 skip=16 count=11 2>/dev/null`" \ = "TeX output " ] then format="dvi" fi fi fi # # ok, now we should *really* know what the file type is. # if [ -z "$format" ] ; then $echo "$file: cannot determine file format (extend source)" >&2 # # if stdin is a tty, ask the user for the file type # if tty -s then $echo "$file: please enter type: " >&2 read format else exit 7 fi fi $echo "$file is format: $format" target=$spooldir/i-$F_NO- if case $format in ps | ascii | pbm | pgm | ppm |\ g3 | dvi | lj | xwd | gif | tif ) fs_cvt_$format $file $target $normal_res ;; *) $echo "$0: unknown format: $format!" >&2 ; exit 8 ;; esac then : ; else $echo "\n$0: error spooling \"$file\" - aborting!" >&2 ; exit 8 fi # next temporary file number (using awk 'cause expr can't do "%04d"!) F_NO=`echo $F_NO | $AWK '{ printf "%04d", $1 + 1 }' -` done # # copy source files over (if requested) # if [ ! -z "$copy_source" ] ; then $echo "\nCopy source files (for printing, if faxing fails)..." mkdir $spooldir/.source-files for file do b=`basename $file` cp $file $spooldir/.source-files/$b done fi # # OK, all files are in the target directory now... # # Now let's create the work file # job=$spooldir/JOB # # conversion complete. Post-process G3 files # pages=`ls $spooldir` # # get list / number of pages # cd $spooldir nr=0 maxnr=`ls | wc -l | tr -d " "` # # generate cover page # # dispose arguments (-C "pgm args") PGM=`expr "$MAKE_COVER_PG" : "\([^ ]*\)"` # if [ ! -z "$PGM" ] then if [ -x "$PGM" ] then $echo "\nGenerating cover page..." export normal_res maxnr=`expr $maxnr + 1` $MAKE_COVER_PG $maxnr "$FAX_STATION_ID" "$FULLNAME" \ "$phone" "$verbose_to" "`date +%D`" "`date +%T`" >cover.g3 if [ -s cover.g3 ] then pages="cover.g3 $pages" else $echo "generating cover page failed!" >&2 maxnr=`expr $maxnr - 1` fi fi fi # # concatenate header with pages # if [ -z "$FAX_HEADER" ] then finalpg="$pages" # don't :) else $echo "\nPutting Header lines on top of pages..." hdrfont=$PBMFONT_HEADER_F test -z "$normal_res" || hdrfont=$PBMFONT_HEADER_N finalpg="" for f in $pages do nr=`expr $nr + 1` cat $FAX_HEADER | sed -e "s;@T@;$phone;g" -e "s;@P@;$nr;g" \ -e "s;@M@;$maxnr;g" -e "s;@U@;$USER;g" \ -e "s;@N@;$FULLNAME;g" \ -e "s;@D@;$verbose_to;g" \ -e "s;@ID@;$FAX_STATION_ID;g" \ -e "s;@DATE@;`date`;g" \ | pbmtext -font $hdrfont | pbm2g3 \ | g3cat - $f > f$nr.g3 \ && rm $f finalpg="$finalpg f$nr.g3" done fi # end "if ! -z $FAX_HEADER" if [ -z "$finalpg" -a -z "$poll_req" ] then $echo "\nnothing to do (no cover page, no data)." >&2 cd $FAX_SPOOL_OUT rmdir $spooldir exit 52 fi # # final step: create JOB file # $echo "phone $phone" >$job.q $echo "user $user" >>$job.q [ "$user" != "$USER" ] && $echo "mail $USER" >>$job.q $echo "input $input_data" >>$job.q $echo "pages " $finalpg >>$job.q [ -z "$verbose_to" ] || \ $echo "verbose_to $verbose_to" >>$job.q [ -z "$poll_req" ] || \ $echo "poll" >>$job.q [ -z "$normal_res" ] || \ $echo "normal_res" >>$job.q [ -z "$TIME" ] || \ $echo "time $TIME" >>$job.q [ -z "$ACCT_HANDLE" ] || \ $echo "acct_handle $ACCT_HANDLE" >>$job.q mv $job.q $job if [ -z "`find $FAX_SPOOL_OUT/.last_run -ctime -1 -print 2>/dev/null`" ] then cat <