"Fossies" - the Fresh Open Source Software Archive

Member "hylafax-7.0.2/util/common-functions.sh.in" (13 Dec 2019, 24999 Bytes) of package /linux/misc/hylafax-7.0.2.tar.gz:


As a special service "Fossies" has tried to format the requested text file into HTML format (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 #! @SCRIPT_SH@
    2 #    $Id: common-functions.sh.in 1159 2013-05-11 21:05:30Z faxguy $
    3 
    4 #
    5 # This holds various functions that are common to the
    6 # various bin scripts.
    7 #
    8 
    9 #
   10 # Produce mailable encoding for binary files.
   11 #
   12 encode()
   13 {
   14     if [ ! -f "$1" ]; then
   15 	return	# encode what?
   16     fi
   17     if [ -x "$MIMENCODE" ]; then
   18 	$MIMENCODE < $1 2>$ERRORSTO
   19     elif [ -x "$UUENCODE" ]; then
   20 	if [ "$ENCODING" = "base64" ]; then
   21 	    $UUENCODE -m $1 ==== | $GREP -v "====$" 2>$ERRORSTO
   22 	else
   23 	    $UUENCODE $1 $1 2>$ERRORSTO
   24 	fi
   25     else
   26 	# Do not use "-x" for backward compatibility; even if it fails
   27 	# this is last chance to encode data, so there's nothing to lose.
   28 	$MIMENCODE < $1 2>$ERRORSTO
   29     fi
   30 }
   31 
   32 #
   33 # For getting all of the "faxinfo" items to line up.  As the CallID tags
   34 # can be customized we must take unmodified faxinfo output into account.
   35 #
   36 setInfoSize()
   37 {
   38     INFOSIZE=`$INFO -n $1 | $SED 's/:.*//g' | $SED q | $AWK 'BEGIN {L=0} length>L {L=length} END {print L}'`
   39     for ITEM in DICTSENDER DICTPAGES DICTQUALITY DICTSIZE DICTRECEIVED \
   40 		DICTTIMETORECV DICTSIGNALRATE DICTDATAFORMAT DICTERRCORRECT \
   41 		DICTCALLID1 DICTCALLID2 DICTCALLID3 DICTCALLID4 DICTCALLID \
   42 		DICTCALLID6 DICTCALLID7 DICTRECEIVEDON DICTCOMMID; do
   43 	THISLEN="`eval echo \\\""$"$ITEM\\\" | $AWK 'BEGIN {L=0} length>L {L=length} END {print L}' | $SED 's/ //g'`"
   44 	if [ $THISLEN -gt $INFOSIZE ]; then INFOSIZE=$THISLEN; fi
   45     done
   46 }
   47 
   48 #
   49 # For getting all of the notify job items to line up.
   50 #
   51 setItemSize()
   52 {
   53     ITEMSIZE=0
   54     for ITEM in DICTDESTINATION DICTJOBID DICTGROUPID DICTSENDER DICTMAILADDR \
   55 		DICTCOMMID DICTMODEM DICTSUBMITTEDFROM DICTPAGEWIDTH \
   56 		DICTPAGELENGTH DICTRES DICTSTATUS DICTDIALOGS DICTDIALS \
   57 		DICTCALLS DICTPAGES DICTATTEMPTS DICTDIRNUM DICTRECEIVER DICTQUALITY \
   58 		DICTPAGEWIDTH DICTPAGELENGTH DICTDATAFORMAT DICTREMOTEEQUIPMENT \
   59 		DICTREMOTESTATION DICTSIGNALRATE; do
   60 	THISLEN="`eval echo \\\""$"$ITEM\\\" | $AWK 'BEGIN {L=0} length>L {L=length} END {print L}' | $SED 's/ //g'`"
   61 	if [ $THISLEN -gt $ITEMSIZE ]; then ITEMSIZE=$THISLEN; fi
   62     done
   63 }
   64 
   65 faxInfo()
   66 {
   67     $INFO -n $1 | $SED -e 's/^ *//g' \
   68 		-e "s/^ *Sender:/$DICTSENDER:/" \
   69 		-e "s/^Pages:/$DICTPAGES:/" \
   70 		-e "s/^Quality:/$DICTQUALITY:/" \
   71 		-e "s/^Page:/$DICTSIZE:/" \
   72 		-e "s/^Received:/$DICTRECEIVED:/" \
   73 		-e "s/^TimeToRecv:/$DICTTIMETORECV:/" \
   74 		-e "s/^SignalRate:/$DICTSIGNALRATE:/" \
   75 		-e "s/^DataFormat:/$DICTDATAFORMAT:/" \
   76 		-e "s/^ErrCorrect:/$DICTERRCORRECT:/" \
   77 		-e "s/^CallID1:/$DICTCALLID1:/" \
   78 		-e "s/^CallID2:/$DICTCALLID2:/" \
   79 		-e "s/^CallID3:/$DICTCALLID3:/" \
   80 		-e "s/^CallID4:/$DICTCALLID4:/" \
   81 		-e "s/^CallID5:/$DICTCALLID5:/" \
   82 		-e "s/^CallID6:/$DICTCALLID6:/" \
   83 		-e "s/^CallID7:/$DICTCALLID7:/" \
   84 		-e "s/ Yes$/ $DICTYES/" \
   85 		-e "s/ No$/ $DICTNO/" \
   86 		-e "s/ Normal$/ $DICTNORMAL/" \
   87 		-e "s/ Fine$/ $DICTFINE/" \
   88 		-e 's/:/|/' | \
   89 		printFormatted $INFOSIZE
   90 }
   91 
   92 printFormatted()
   93 {
   94     $AWK -F\| -v s=$1 'BEGIN { size = s; } { ilen=length($1); printf "%"size-ilen"s%s:%s\n", "",$1,$2 }'
   95 }
   96 
   97 #
   98 # Export qfile content to environment
   99 # parseQfile(prefix, filename)
  100 # Both parameters can be omitted. Defaults to no prefix and $QFILE.
  101 #
  102 parseQfile()
  103 {
  104     # In shell scripts, there are no special characters in hard-quoted
  105     # strings (quoted with (')). Single-quotes can't even be escaped
  106     # inside such strings and must be put outside of them. We thus replace
  107     # (') with ('\'') which terminates the current string, adds a single
  108     # quote and starts a new string.
  109     #
  110     # We no longer escape newlines, because we don't eval
  111     #
  112     # print out variable name and value so we can eval it in the shell
  113     #
  114     VAR_PREFIX="$1"
  115     if [ -n "$2" ] ; then
  116         FILENAME=$2;
  117     else
  118         FILENAME=$QFILE;
  119     fi
  120     if [ ! -f "$FILENAME" ] ; then
  121         return # cannot do much more without a file
  122     fi
  123     $AWK -F: '
  124     function p(varname,val)
  125     {
  126         gsub(/\047/, "\047\\\047\047", val);
  127         # mawk sees 047 as decimal 47 rather than octal, so we use the decimal
  128         # value of the quote character: 39.
  129         printf "%s%s=%c%s%c\n",var_prefix,varname,39,val,39
  130         printf "export %s%s\n",var_prefix,varname
  131     }
  132     BEGIN {
  133         var_prefix="'"$VAR_PREFIX"'";
  134         nfiles = 0;
  135         npins = 0;
  136     }
  137     /^nsf/	{ p("equipment", $3); p("station", $5); next; }
  138     /^external/    { p("number", $2); next; }      # override unprocessed number
  139     /^regarding/    { regarding = $0; sub("regarding:", "", regarding); p("regarding", regarding); next; }
  140     /^jobtag/    { jobtag = $0; sub("jobtag:", "", jobtag); p("jobtag", jobtag); next; }
  141     # status needs to be used in the shell as faxstatus since status is reserved word
  142     /^status:/    { status = $0; sub("status:", "", status);
  143               while ($0 ~ /\\\\$/ && getline > 0) {
  144                   sub(/\\\\$/, "\\n", status);
  145                   status = status $0;
  146               } p("faxstatus", status);
  147               next;
  148             }
  149     /^[!]*post/    { p("files_"++nfiles, $4); p("filetype_"nfiles, "PostScript"); next; }
  150     /^[!]*tiff/    { p("files_"++nfiles, $4); p("filetype_"nfiles, "TIFF"); next; }
  151     /^[!]*pdf/    { p("files_"++nfiles, $4); p("filetype_"nfiles, "PDF"); next; }
  152     /^[!]*pcl/    { p("files_"++nfiles, $4); p("filetype_"nfiles, "PCL"); next; }
  153     /^page:/    { p("pins_"++npins, $4); next; }
  154     /^data:/    { p("files_"++nfiles, $4); next; }
  155     /^poll/        { p("poll", " -p"); next; }
  156     # Only parse remaining valid lines and allows for colons to appear in the value part
  157     /^[a-z]+:/     { str = $0; sub($1":", "", str); p($1, str); next; }
  158     {printf "# Invalid line> %s\n", $0;}
  159     END { p("nfiles", nfiles); p("npins", npins) } ' $FILENAME > $TMPDIR/qfile-awk.sh
  160     . $TMPDIR/qfile-awk.sh
  161 }
  162 
  163 #
  164 # Produce faxable TIFF (MH, MR, MMR) from a PDF or Postscript file.
  165 #
  166 gs2fax()
  167 {
  168     #
  169     # Features and bugs can vary from version to version with Ghostscript.
  170     # So we need to know what version we're dealing with here.
  171     #
  172     GSMAJVER="`$PS -v | $SED q | $SED -e 's/^.*Ghostscript.* \([0-9]*\)\.\([0-9]*\).*/\1/' -e 's/^0*//'`"
  173     GSMINVER="`$PS -v | $SED q | $SED -e 's/^.*Ghostscript.* \([0-9]*\)\.\([0-9]*\).*/\2/' -e 's/^0*//'`"
  174 
  175     test -z "$files" && files="-"	# read from stdin
  176     case "${pagewidth}x${pagelength}" in
  177 	1728x280|1728x279|2592x280|2592x279|3456x280|3456x279)	# 279.4mm is actually correct...
  178 	    paper=letter;;
  179 	1728x364|2592x364|3456x364) 
  180 	    paper=legal;;
  181 	*x296|*x297)			# more roundoff problems...
  182 	    paper=a4;;
  183 	*x364)
  184 	    paper=b4;;
  185 	2432x*|3648x*|4864x*)
  186 	    paper=a3;;
  187 	*)
  188 	    echo "$0: Unsupported page size: $pagewidth x $pagelength";
  189 	    exit 254;;			# causes document to be rejected
  190     esac
  191     #
  192     # The image must end up with a pixel width according to T.32 Table 21.
  193     # Ghostscript contains code to fixate A4 and letter to 1728 pixels
  194     # when using 196-204 dpi and tiffg3/4.  It supposedly does the same for
  195     # B4 but not for A3, thus the floats are needed (for A3's benefit).
  196     # However, this behavior does nothing for US legal as well as the myriad
  197     # other page sizes (other than A4, US Letter, and B4) that we sometimes
  198     # see.  So we have to carefully ensure that our formatting will be right.
  199     #
  200     # How we go about using Ghostscript to accomplish that requirement can 
  201     # be tricky, complicated, and sometimes problematic.  Depending on which 
  202     # Ghostcript version is being used there are various approaches in getting 
  203     # all pages sized properly.  We generally either use a combination of 
  204     # -dEPSFitPage and -dPDFFitPage, and for newer Ghostscript versions we can 
  205     # also use -dAdjustWidth.  These make it so that the image is resized 
  206     # to fit the page media and prevents page sizing within the documents from 
  207     # altering the command-line page-size specification.  (In the past 
  208     # -dFIXEDMEDIA was used for this purpose, but -dFIXEDMEDIA doesn't resize 
  209     # documents, it just cuts them.)  The benefit to -dAdjustWidth is that it
  210     # permits TIFFs to be made with pages of varied length (such as mixed letter
  211     # and legal).
  212     #
  213     # We use -dUseCropBox to prevent utilization of the full MediaBox (as they
  214     # can differ).  Remove this if there is regularly desireable content 
  215     # outside the CropBox.
  216     #
  217     if [ "$GSMAJVER" -eq 8 ] && [ "$GSMINVER" -eq 70 ]; then
  218 	# There's a bug with -dUseCropBox on 8.70 when it finds no MediaBox/CropBox.
  219 	FIXEDWIDTH=""
  220     else
  221 	FIXEDWIDTH="-dUseCropBox"
  222     fi
  223     if [ "$GSMAJVER" -gt 9 ] || [ "$GSMAJVER" -eq 9 ] && [ "$GSMINVER" -ge 4 ]; then
  224 	# We shouldn't need to use the "FitPage" options with AdjustWidth, but if we 
  225 	# don't then some PDFs won't auto-rotate for some unknown reason. (Ghostscript
  226 	# bug?) Unfortunately, with the "FitPage" options there is no possibility for 
  227 	# faxes with pages of mixed lengths.  This will, for example, cause legal-sized
  228 	# pages to be reduced to fit on A4.  As the need for mixed lengths is probably
  229 	# less-common than the need to auto-rotate the problematic PDFs we opt to
  230 	# serve the more common case here by default.  If mixed lengths are 
  231 	# specifically desired then remove the "FitPage" options here and test that 
  232 	# the input PDFs you use do not trip on the auto-rotate problem.
  233 	FIXEDWIDTH="$FIXEDWIDTH -dEPSFitPage -dPDFFitPage -dAdjustWidth=$pagewidth"
  234     else
  235 	FIXEDWIDTH="$FIXEDWIDTH -dEPSFitPage -dPDFFitPage"
  236     fi
  237 
  238     case "$paper" in
  239 	a4)
  240 	    case "$pagewidth" in
  241 		2592) hres=313.65;;		# VR_300X300
  242 		3456) hres=418.20;;		# VR_R16
  243 		*) hres=204;;			# everything else, 1728 pixels (should be 209.10)
  244 	    esac;;
  245 	b4)
  246 	    case "$pagewidth" in
  247 		3072) hres=311.97;;		# VR_300X300
  248 		4096) hres=415.95;;		# VR_R16
  249 		*) hres=204;;			# everything else, 2048 pixels (should be 207.98)
  250 	    esac;;
  251 	a3)
  252 	    case "$pagewidth" in
  253 		3648) hres=311.94;;		# VR_300X300
  254 		4864) hres=415.93;;		# VR_R16
  255 		*) hres=207.96;;		# everything else, 2432 pixels
  256 	    esac;;
  257 	*)					# letter, legal
  258 	    case "$pagewidth" in
  259 		2592) hres=304.94;;		# VR_300X300
  260 		3456) hres=406.59;;		# VR_R16
  261 		*) hres=203.29;;		# everything else, 1728 pixels
  262 	    esac;;
  263     esac
  264 
  265     #
  266     # The sed work fixes bug in Windows-generated
  267     # PostScript that causes certain international
  268     # character marks to be placed incorrectly.
  269     #
  270     #    | $SED -e 's/yAscent Ascent def/yAscent 0 def/g' \
  271     #
  272     # NB: unfortunately it appears to break valid PostScript;
  273     #     so it's been disabled.
  274 
  275     #
  276     # We must ensure that the entire page is written in a single
  277     # strip.  This was the default behavior before Ghostscript 8.71.
  278     # The default changed in the 8.71 release, so now we specify it.
  279     STRIPSIZE="-dMaxStripSize=0"
  280 
  281     #
  282     # Sometimes the client supplies documents which has pages which are
  283     # not all oriented portrait.  Because fax is typically portrait-only,
  284     # and because we'd prefer to fit as much of the image on the source
  285     # page onto the faxed page instead of cutting the image off or
  286     # unnecessarily shrinking the image we use a Ghostscript script
  287     # in order to automatically rotate the pages to portrait orientation.
  288     # This feature can be disabled with AUTOROTATE="" in etc/FaxModify and
  289     # only works for Ghostscript 8 and later.
  290     #
  291     if [ "$GSMAJVER" -gt 7 ]; then
  292 	AUTOROTATE="bin/auto-rotate.ps"
  293     else
  294 	AUTOROTATE=""
  295     fi
  296 
  297     #
  298     # Ghostscript's default dithering with the fax drivers is 
  299     # usually unsatisfactory.  So we have an option to process
  300     # the image through libtiff's Floyd-Steinberg dithering.
  301     # This will be a bit more costly on CPU and image preparation
  302     # time... enable it cautiously.
  303     #
  304     # An alternative to libtiff Floyd-Steinberg dithering would
  305     # be to use a threshold array based stochastic mask within
  306     # Ghostscript.  However, this alternative may perform less 
  307     # than ideally on unmodified Ghostscript versions prior to 8.62.
  308     # See: http://bugs.ghostscript.com/show_bug.cgi?id=689633
  309     #
  310     DITHERING=default
  311 
  312     #
  313     # Apply customizations such as watermarking.
  314     #
  315     if [ -f etc/FaxModify ]; then
  316 	. etc/FaxModify
  317     fi
  318 
  319     if [ "$color" = "yes" ]; then
  320 	# We should prepare a color image - possibly in addition to monochrome.
  321 	# Square resolutions are mandatory per ITU T.30 Table 2 Notes 25 and 34,
  322 	# so we use hres for vertical resolution as well.
  323 	case "$paper" in
  324 	    a4) chres=209.10;;		# 1728 pixels
  325 	    b4) chres=207.98;;		# 2048 pixels
  326 	    a3) chres=207.96;;		# 2432 pixels
  327 	    *)  chres=203.29;;		# 1728 pixels
  328 	esac
  329 	outfile=$out
  330 	if [ "$device" != "tiff24nc" ]; then
  331 	    # Indicates color-only
  332 	    outfile="$out.color"
  333 	fi
  334 	$PS -q -sDEVICE=tiff24nc -dNOPAUSE -dSAFER=true -sPAPERSIZE=$paper \
  335 	    -dBATCH -r$chres\x$chres "-sOutputFile=$outfile" $STRIPSIZE $FIXEDWIDTH $AUTOROTATE $files
  336 	if [ "$device" = "tiff24nc" ]; then
  337 	    $RM -f "$out.color"
  338 	    return
  339 	fi
  340     else
  341 	$RM -f "$out.color"
  342     fi
  343     if [ "$DITHERING" = "gs-stocht" ]; then
  344 	$CAT $files | $PS -q \
  345 	    -sDEVICE=$device \
  346 	    -dNOPAUSE \
  347 	    -dSAFER=true \
  348 	    -sPAPERSIZE=$paper \
  349 	    -dBATCH \
  350 	    -r$hres\x$vres \
  351 	    "-sOutputFile=$out" \
  352 	    $STRIPSIZE \
  353 	    $FIXEDWIDTH \
  354 	    $AUTOROTATE \
  355 	    stocht.ps -c "<< /HalftoneMode 1 >> setuserparams" -
  356 	return
  357     fi
  358     if [ "$DITHERING" = "libtiff-fs" ] && ($PS -h | $GREP tiff24nc >/dev/null 2>&1) && \
  359        [ -x $TIFFBIN/tiff2bw ] && [ -x $TIFFBIN/tiffdither ] && [ -x $TIFFBIN/tiff2ps ] && \
  360        [ -x $TIFFBIN/tiffsplit ] && [ -x $TIFFBIN/tiffcp ]; then
  361 	$PS -q -sDEVICE=tiff24nc -dNOPAUSE -dSAFER=true -sPAPERSIZE=$paper \
  362 	    -dBATCH -r$hres\x$vres "-sOutputFile=$out.1" $STRIPSIZE $FIXEDWIDTH $AUTOROTATE $files
  363 	# Both tiff2bw and tiffdither only operate on single pages, so...
  364 	mkdir tmpdir.$$
  365 	cd tmpdir.$$
  366 	$TIFFBIN/tiffsplit ../$out.1
  367 	for i in *; do
  368 	    $TIFFBIN/tiff2bw $i $i.2
  369 	    $TIFFBIN/tiffdither $i.2 $i.3
  370 	    $RM -f $i $i.2
  371 	done
  372 	$TIFFBIN/tiffcp * ../$out.2
  373 	$RM -f *
  374 	cd ..
  375 	rmdir tmpdir.$$
  376 	#
  377 	# Unfortunately, this process leaves the image with Photometric of min-is-black, which
  378 	# is opposite from what we need for faxing.  So we have to run it again through gs.
  379 	#
  380 	$TIFFBIN/tiff2ps -a $out.2 > $out.3
  381 	files=$out.3
  382     else
  383 	DITHERING=default
  384     fi
  385 
  386     $PS -q \
  387 	-sDEVICE=$device \
  388 	-dNOPAUSE \
  389 	-dSAFER=true \
  390 	-sPAPERSIZE=$paper \
  391 	-dBATCH \
  392 	-r$hres\x$vres \
  393 	"-sOutputFile=$out" \
  394 	$STRIPSIZE \
  395 	$FIXEDWIDTH \
  396 	$AUTOROTATE \
  397 	$files
  398 
  399     if [ "$DITHERING" = "libtiff-fs" ]; then
  400 	$RM -f $out.1 $out.2 $out.3
  401     fi
  402     #
  403     # Double-check the Ghostscript output to make sure it's what we need.
  404     # This is important, because, for example, if we don't have the 
  405     # necessary pixel-width then the fax wouldd likely fail.
  406     #
  407     CHECK=$SBIN/tiffcheck       # program to check acceptability
  408     PS2FAX=                     # null to prevent recursion
  409     TIFFCP=$TIFFBIN/tiffcp      # part of the TIFF distribution
  410     TIFF2PS=$TIFFBIN/tiff2ps    # ditto
  411     TIFFINFO=$TIFFBIN/tiffinfo  # ditto
  412     
  413     fil=$out
  414 
  415     tiffCheck
  416 }
  417 
  418 tiffCheck()
  419 {
  420     CLEARTMP=no
  421     if [ "$fil" = "$out" ]; then
  422 	CLEARTMP=yes
  423 	fil="$fil.$$.tmp"
  424 	$MV $out $fil
  425     fi
  426     #
  427     # tiffcheck looks over a TIFF document and prints out a string
  428     # that describes what's needed (if anything) to make the file
  429     # suitable for transmission with the specified parameters (page
  430     # width, page length, resolution, encoding).  This string may
  431     # be followed by explanatory messages that can be returned to
  432     # the user.  The possible actions are:
  433     #
  434     # OK		document is ok
  435     # REJECT	something is very wrong (e.g. not valid TIFF)
  436     # REFORMAT	data must be re-encoded
  437     # REVRES	reformat to change vertical resolution
  438     # RESIZE	scale or truncate the pages
  439     # REIMAGE	image is not 1-channel bilevel data
  440     #
  441     # Note that these actions may be combined with "+";
  442     # e.g. REFORMAT+RESIZE.  If we cannnot do the necessary work
  443     # to prepare the document then we reject it here.
  444     #
  445     RESULT=`$CHECK $opt $fil 2>/dev/null`
  446 
  447     ACTIONS=`echo "$RESULT" | $SED 1q`
  448     case "$ACTIONS" in
  449     OK)				# no conversion needed
  450 	#
  451 	# 1) We don't use hard links because it screws up faxqclean
  452 	#    logic that assumes the only hard links are used 
  453 	#    temporarily when document files are being created during
  454 	#    the job submission process.
  455 	# 2) We don't use symbolic links because the links get broken
  456 	#    when the source document is shared between jobs and
  457 	#    faxq removes the source document before all jobs complete.
  458 	#
  459 	# If we ever encounter problems where the client submits corrupt
  460 	# TIFF and we need to clean it up before transmission, then we
  461 	# can simply merge OK with REFORMAT.  For now we use $CP instead
  462 	# of $TIFFCP, however, to provide the client some control.
  463 	# The -p is needed or ownership and permissions can be lost.
  464 	#
  465 	$CP -p -f $fil $out
  466 	if [ "$CLEARTMP" = "yes" ]; then $RM -f $fil; fi
  467 	exit 0			# successful conversion
  468 	;;
  469     *REJECT*)			# document rejected out of hand
  470 	echo "$RESULT" | $SED 1d
  471 	if [ "$CLEARTMP" = "yes" ]; then $RM -f $fil; fi
  472 	exit 254			# reject document
  473 	;;
  474     REFORMAT)			# only need format conversion (e.g. g4->g3)
  475 	rowsperstrip="-r 9999 "
  476 	if [ -n "`$TIFFINFO $fil | $GREP 'Compression Scheme: ISO JBIG'`" ]; then
  477 	    rowsperstrip=""
  478 	fi
  479 	$TIFFCP -i -c $df -f lsb2msb $rowsperstrip$fil $out
  480 
  481 	# libtiff 3.5.7 gives exit status 9 when there are unknown tags...
  482 	exitcode=$?
  483 	if [ "$CLEARTMP" = "yes" ]; then $RM -f $fil; fi
  484 	if [ $exitcode != 0 ] && [ $exitcode != 9 ]; then {
  485 	    $CAT<<EOF
  486 Unexpected failure converting TIFF document; the command
  487 
  488     $TIFFCP -i -c $df -f lsb2msb $rowsperstrip$fil $out
  489 
  490 failed with exit status $?.  This conversion was done because:
  491 
  492 EOF
  493 	    echo "$RESULT" | $SED 1d; exit 254
  494 	}
  495 	fi
  496 	exit 0
  497 	;;
  498     #
  499     # REVRES|REFORMAT+REVRES	adjust vertical resolution (should optimize)
  500     # *RESIZE			page size must be adjusted (should optimize)
  501     # *REIMAGE			maybe should reject (XXX)
  502     #
  503     *REVRES|*RESIZE|*REIMAGE)
  504 	if [ -z "$PS2FAX" ]; then
  505 	    echo "Unable to format with converters."
  506 	    echo "Preventing recursion."
  507 	    if [ "$CLEARTMP" = "yes" ]; then $RM -f $fil; fi
  508 	    exit 254
  509 	fi
  510 	#
  511 	# Previously we used tiff2ps here instead of tiff2pdf, however, this was problematic
  512 	# with conversion of TIFFs which were not the same size as the target page.  To fix 
  513 	# this it would have required pushing image dimensions to Ghostscript for it to use
  514 	# the -g option, and that would require a lot of converter-script modifications.  It 
  515 	# is easier to simply use tiff2pdf because the PDF output includes the image 
  516 	# dimensions which are then fed to Ghostscript.  (Which would have also been 
  517 	# accomplished with the tiff2ps -2 or -3 options, however, in those cases tiff2ps 
  518 	# resizes the image to fit on the page, and other options, -h and -w, which may not 
  519 	# be available to all tiff2ps versions would have needed to be used.)
  520 	#
  521 	($TIFF2PDF -o $out.$$.pdf $fil; $PDF2FAX -o $out -i "$jobid" $opt $out.$$.pdf && $RM -f $out.$$.pdf) || {
  522 	    $CAT<<EOF
  523 Unexpected failure converting TIFF document; the command
  524 
  525     $TIFF2PDF -o $out.$$.pdf $fil; $PDF2FAX -o $out -i "$jobid" $opt $out.$$.pdf && $RM -f $out.$$.pdf
  526 
  527 failed with exit status $?.  This conversion was done because
  528 
  529 EOF
  530 	    echo "$RESULT" | $SED 1d; exit 254
  531 	}
  532 	if [ "$CLEARTMP" = "yes" ]; then $RM -f $fil; fi
  533 	exit 0
  534 	;;
  535     *)				# something went wrong
  536 	echo "Unexpected failure in the TIFF format checker;"
  537 	echo "the output of $CHECK was:"
  538 	echo ""
  539 	echo "$RESULT"
  540 	echo ""
  541 	if [ "$CLEARTMP" = "yes" ]; then $RM -f $fil; fi
  542 	exit 254			# no formatter
  543 	;;
  544     esac
  545 }
  546 
  547 SetupPrivateTmp()
  548 {
  549     if [ -d "$HYLAFAX_TMPDIR" ]; then
  550         # Private temp area already created.
  551         return
  552     fi
  553 
  554     # Would have liked to use -t, but older mktemp don't support it.
  555     if [ -z "$TMPDIR" ] || [ ! -w "$TMPDIR" ]; then
  556         TMPDIR="/tmp"
  557     fi
  558     HYLAFAX_TMPDIR=`mktemp -d $TMPDIR/hylafaxtmp-XXXXXXXX 2>/dev/null` || {
  559         HYLAFAX_TMPDIR="$TMPDIR/hylafaxtmp-$RANDOM-$RANDOM-$RANDOM-$$"
  560         mkdir -m 0700 "$HYLAFAX_TMPDIR"
  561     }
  562     if [ $? != 0 ]
  563     then
  564 	echo "Couldn't setup private temp area - exiting!" 1>&2
  565 	exit 1
  566     fi
  567     # We want any called programs to use our tmp dir.
  568     TMPDIR=$HYLAFAX_TMPDIR
  569     export TMPDIR
  570 
  571     trap cleanupExit 0
  572     trap "hfExit 1" 1 2 15
  573 }
  574 
  575 CleanupPrivateTmp ()
  576 {
  577     if [ -d "$HYLAFAX_TMPDIR" ]
  578     then
  579 	rm -Rf "$HYLAFAX_TMPDIR"
  580     fi
  581 }
  582 
  583 cleanupExit ()
  584 {
  585     trap - 0 1 2 15
  586     CleanupPrivateTmp
  587 }
  588 
  589 hfExit ()
  590 {
  591     cleanupExit
  592     exit $1
  593 }
  594 
  595 assign_cmd_subst()
  596 {
  597 	# Parameters:
  598 	# variablename 'commandline ...' [ positional parameters ...]
  599 	#
  600 	# 'eval' the commandline and assign its standard output data to the
  601 	# given variable (like command substitution), preserving trailing
  602 	# newlines (unlike command substitution).
  603 	#
  604 	# The positional parameters ("$@") are set to the given positional
  605 	# parameters and then the commandline is evaluated in a subshell
  606 	# execution environment.  Its standard output data is assigned to the
  607 	# given variable.
  608 	#
  609 	# Return the exit code of the commandline.
  610 
  611 	set false "$@"
  612 	# "$1", if executed, signals an error if and only if it returns with
  613 	# exit code 0.
  614 
  615 	if ${2+false} :
  616 	then
  617 		# No parameters have been given:
  618 		printf '%s: %s\n' assign_cmd_subst \
  619 			'Missing variable name.' >&2
  620 		# Signal an error:
  621 		shift; set : "$@"
  622 	elif ! LC_ALL=C expr " $2" : \
  623 		' [[:alpha:]_][[:alnum:]_]*$' > /dev/null
  624 	then
  625 		printf '%s: %s: is not a variable name.\n' \
  626 			assign_cmd_subst "$2" >&2
  627 		# Signal an error:
  628 		shift; set : "$@"
  629 	fi
  630 	if ${3+false} :
  631 	then
  632 		printf '%s: %s\n' assign_cmd_subst \
  633 			'Missing commandline.' >&2
  634 		# Signal an error:
  635 		shift; set : "$@"
  636 	fi
  637 	if "$1"
  638 	then
  639 		# An error occurred.  Fail.
  640 		return 125
  641 	else
  642 		shift
  643 		# "$1" looks like a variable name.
  644 		eval "$1"'="$( ( shift 2; '"$2"' ); ec="$?";' \
  645 			'printf %s .; exit "$ec" )"'
  646 		set "$?" "$1"
  647 		eval "$2"'="${'"$2"'%.}"'
  648 		return "$1"
  649 	fi
  650 }
  651 
  652 set_exit_code()
  653 {
  654 	return ${1+"$1"}
  655 }
  656 
  657 rfc2047_encode()
  658 {
  659 	# RFC2047-encode a part of a header field value.
  660 	#
  661 	# required parameters:
  662 	#
  663 	# * number of already used columns in the current line,
  664 	#
  665 	# * charset name,
  666 	#
  667 	# * header field value to be encoded,
  668 	#
  669 	# optional parameters:
  670 	#
  671 	# * name of a variable to store the number of already used columns in
  672 	#   the last line.
  673 	#
  674 	# The encoded text is sent to standard output.
  675 
  676 	eval "$( rfc2047_encode_2 "$@" )"
  677 } 3>&1
  678 
  679 rfc2047_encode_2()
  680 {
  681 	# Caller environment:
  682 	#
  683 	# File descriptor #3: receives the encoded text.
  684 	#
  685 	# File descriptor #1: receives shell commands for the caller
  686 	# environment to be "eval"ed.
  687 	#
  688 	# required parameters:
  689 	#
  690 	# * number of already used columns in the current line,
  691 	#
  692 	# * charset_name,
  693 	#
  694 	# * header field value to be encoded,
  695 	#
  696 	# optional parameters:
  697 	#
  698 	# * name of a variable to store the number of already used columns in
  699 	#   the last line.
  700 
  701 	set -u &&
  702 	columns_in_use="${1:?missing number of already used columns}" &&
  703 	charset="${2:?missing non-empty charset name}" &&
  704 	value="${3?missing header field value}" &&
  705 	column_variable="${4-}" &&
  706 	prefix=' =?'"$charset"'?Q?' &&
  707 	suffix='?=' &&
  708 	: $(( columns_in_use += ${#prefix} + ${#suffix} )) &&
  709 	printf '%s' "${prefix}" >&3 &&
  710 	while
  711 		character="${value%"${value#?}"}" &&
  712 		# "$character" is the first (maybe multi-byte) character of
  713 		# "$value".
  714 		${character:+:} false &&
  715 		value="${value#"$character"}"
  716 	do
  717 		(
  718 			# In order to process the individual octets of a single
  719 			# (maybe multi-byte) character, change the locale to
  720 			# the POSIX locale:
  721 			export LC_ALL && LC_ALL=C &&
  722 			encoded_character= && length_of_encoded_character=0 &&
  723 			while
  724 				octet="${character%"${character#?}"}" &&
  725 				${octet:+:} false &&
  726 				character="${character#"$octet"}"
  727 			do
  728 				case "$octet" in
  729 					[[:alnum:]])
  730 						;;
  731 					*)
  732 						octet="$( printf '=%.2X' \
  733 							\'"$octet" )"
  734 						;;
  735 				esac
  736 				encoded_character="${encoded_character}${octet}"
  737 			done &&
  738 			printf '%s\n' "$encoded_character"
  739 		)
  740 	done 3>&- |
  741 	{
  742 		{
  743 			while read -r encoded_character
  744 			do
  745 				length_of_encoded_character="${#encoded_character}" &&
  746 				if test $(( columns_in_use += \
  747 					length_of_encoded_character )) -gt 75
  748 				then
  749 					# Appending the encoded character would
  750 					# make the current line too long.
  751 					#
  752 					# Finish the current encoded word
  753 					# without appending the encoded
  754 					# character, then start in a
  755 					# continuation line a new encoded
  756 					# word beginning with the encoded
  757 					# character.
  758 					columns_in_use=$(( ${#prefix} + \
  759 						length_of_encoded_character + \
  760 						${#suffix} ))
  761 					printf '%s\n%s' "$suffix" "$prefix"
  762 				fi &&
  763 				printf '%s' "$encoded_character"
  764 			done &&
  765 			printf '%s' "$suffix"
  766 		} >&3
  767 		{
  768 			ec="$?"
  769 			if ${column_variable:+:} false
  770 			then
  771 				printf '%s=%s\n' "$column_variable" \
  772 					"$columns_in_use"
  773 			fi
  774 			printf 'set_exit_code %s\n' "$ec"
  775 		} 3>&-
  776 	}
  777 }