#! /bin/bash
#    $Id: common-functions.sh.in,v 1.30 2008/02/27 23:04:16 faxguy Exp $

#
# This holds various functions that are common to the
# various bin scripts.
#

#
# Produce mailable encoding for binary files.
#
encode()
{
    if [ ! -f "$1" ]; then
	return	# encode what?
    fi
    if [ -x "$MIMENCODE" ]; then
	$MIMENCODE < $1 2>$ERRORSTO
    elif [ -x "$UUENCODE" ]; then
	if [ "$ENCODING" = "base64" ]; then
	    $UUENCODE -m $1 ==== | $GREP -v "====$" 2>$ERRORSTO
	else
	    $UUENCODE $1 $1 2>$ERRORSTO
	fi
    else
	# Do not use "-x" for backward compatibility; even if it fails
	# this is last chance to encode data, so there's nothing to lose.
	$MIMENCODE < $1 2>$ERRORSTO
    fi
}

#
# For getting all of the "faxinfo" items to line up.  As the CallID tags
# can be customized we must take unmodified faxinfo output into account.
#
setInfoSize()
{
    INFOSIZE=`$INFO -n $1 | $SED 's/:.*//g' | $SED q | wc -L`
    for ITEM in DICTSENDER DICTPAGES DICTQUALITY DICTSIZE DICTRECEIVED \
		DICTTIMETORECV DICTSIGNALRATE DICTDATAFORMAT DICTERRCORRECT \
		DICTCALLID1 DICTCALLID2 DICTCALLID3 DICTCALLID4 DICTCALLID \
		DICTCALLID6 DICTCALLID7 DICTRECEIVEDON DICTCOMMID; do
	THISLEN="`eval echo \\\""$"$ITEM\\\" | wc -L | $SED 's/ //g'`"
	if [ $THISLEN -gt $INFOSIZE ]; then INFOSIZE=$THISLEN; fi
    done
}

#
# For getting all of the notify job items to line up.
#
setItemSize()
{
    ITEMSIZE=0
    for ITEM in DICTDESTINATION DICTJOBID DICTGROUPID DICTSENDER DICTMAILADDR \
		DICTCOMMID DICTMODEM DICTSUBMITTEDFROM DICTPAGEWIDTH \
		DICTPAGELENGTH DICTRES DICTSTATUS DICTDIALOGS DICTDIALS \
		DICTCALLS DICTPAGES DICTATTEMPTS DICTDIRNUM DICTRECEIVER DICTQUALITY \
		DICTPAGEWIDTH DICTPAGELENGTH DICTDATAFORMAT DICTREMOTEEQUIPMENT \
		DICTREMOTESTATION DICTSIGNALRATE; do
	THISLEN="`eval echo \\\""$"$ITEM\\\" | wc -L | $SED 's/ //g'`"
	if [ $THISLEN -gt $ITEMSIZE ]; then ITEMSIZE=$THISLEN; fi
    done
}

faxInfo()
{
    $INFO -n $1 | $SED -e 's/^ *//g' \
		-e "s/^ *Sender:/$DICTSENDER:/" \
		-e "s/^Pages:/$DICTPAGES:/" \
		-e "s/^Quality:/$DICTQUALITY:/" \
		-e "s/^Page:/$DICTSIZE:/" \
		-e "s/^Received:/$DICTRECEIVED:/" \
		-e "s/^TimeToRecv:/$DICTTIMETORECV:/" \
		-e "s/^SignalRate:/$DICTSIGNALRATE:/" \
		-e "s/^DataFormat:/$DICTDATAFORMAT:/" \
		-e "s/^ErrCorrect:/$DICTERRCORRECT:/" \
		-e "s/^CallID1:/$DICTCALLID1:/" \
		-e "s/^CallID2:/$DICTCALLID2:/" \
		-e "s/^CallID3:/$DICTCALLID3:/" \
		-e "s/^CallID4:/$DICTCALLID4:/" \
		-e "s/^CallID5:/$DICTCALLID5:/" \
		-e "s/^CallID6:/$DICTCALLID6:/" \
		-e "s/^CallID7:/$DICTCALLID7:/" \
		-e "s/ Yes$/ $DICTYES/" \
		-e "s/ No$/ $DICTNO/" \
		-e "s/ Normal$/ $DICTNORMAL/" \
		-e "s/ Fine$/ $DICTFINE/" \
		-e 's/:/|/' | \
		printFormatted $INFOSIZE
}

printFormatted()
{
    $AWK -F\| -v s=$1 'BEGIN { size = s; } { ("echo \""$1"\" | wc -L") | getline ilen; close("echo \""$1"\" | wc -L"); printf "%"size-ilen"s%s:%s\n", "",$1,$2 }'
}

parseQfile()
{
    # In shell scripts, there are no special characters in hard-quoted
    # strings (quoted with (')). Single-quotes can't even be escaped
    # inside such strings and must be put outside of them. We thus replace
    # (') with ('\'') which terminates the current string, adds a single
    # quote and starts a new string.
    #
    # print out variable name and value so we can eval it in the shell
    VAR_PREFIX="$1"
    AWK_OUTPUT=`$AWK -F: ' 
    function p(varname,val)
    {
        gsub(/\\047/, "\047\\\\\047\047", val);
        printf "%s%s=\\047%s\\047\n",var_prefix,varname,val
    }
    BEGIN {
	var_prefix = "'"${VAR_PREFIX}"'";
        tts = 0;
        nfiles = 0;
        npins = 0;
        pagewidth = 0;
        pagelength = 0;
        resolution = 0;
        jobtype = "facsimile";
        signalrate = "unknown";
        dataformat = "unknown";
        doneop = "default";
        pagernum = "unknown";
        commid = "";
	csi = "";
	equipment = "";
	station = "";
    }
    /^tts/	{ p("tts",$2); }
    /^csi/	{ p("csi",$2); }
    /^nsf/	{ p("equipment",$3); }
    /^nsf/	{ p("station",$5); }
    /^jobid/    { p("jobid",$2); }
    /^groupid/    { p("groupid", $2); }
    /^state/    { p("state", $2+0); }  
    /^doneop/    { p("doneop", $2); }
    /^number/    { p("number", $2); }
    /^faxnumber/ { p("faxnumber", $2); }
    /^faxname/   { p("faxname", $2); }
    /^canonical/    { p("canonical", $2); }
    /^external/    { p("number", $2); }        # override unprocessed number
    /^receiver/    { p("receiver", $2); }
    /^company/    { p("company", $2); }
    /^sender/    { p("sender", $2); }
    /^mailaddr/    { p("mailaddr", $2); }
    /^owner/    { p("owner", $2); }
    /^regarding/ { regarding = $0; sub("regarding:", "", regarding); p("regarding", regarding)}
    /^jobtag/    { jobtag = $0; sub("jobtag:", "", jobtag); p("jobtag", jobtag)}
    /^jobtype/    { p("jobtype", $2); }
    # status needs to be used in the shell as faxstatus since status is reserved word
    /^status/    { status = $0; sub("status:", "", status);
              while ($0 ~ /\\\\$/ && getline > 0) {
                  sub(/\\\\$/, "\\n", status);
                  status = status $0;
              } p("faxstatus", status);
            }
    /^errorcode/    { p("errorcode", $2); }
    /^resolution/    { p("resolution", $2); }
    /^npages/    { p("npages", $2); }
    /^totpages/    { p("totpages", $2); }
    /^dirnum/    { p("dirnum", $2); }
    /^commid/    { p("commid", $2); }
    /^ntries/    { p("ntries", $2); }
    /^ndials/    { p("ndials", $2); }
    /^maxdials/    { p("maxdials", $2); }
    /^maxtries/    { p("maxtries", $2); }
    /^pagewidth/    { p("pagewidth", $2); }
    /^pagelength/    { p("pagelength", $2); }
    /^signalrate/    { p("signalrate", $2); }
    /^dataformat/    { p("dataformat", $2); }
    /^modem/    { p("modem", $2); }
    /^modemused/    { p("modemused", $2); }
    /^totdials/    { p("totdials", $2); }
    /^tottries/    { p("tottries", $2); }
    /^client/    { p("client", $2); }
    /^[!]*post/    { p("files_"++nfiles, $4); p("filetype_"nfiles, "PostScript"); }
    /^[!]*tiff/    { p("files_"++nfiles, $4); p("filetype_"nfiles, "TIFF"); }
    /^[!]*pdf/    { p("files_"++nfiles, $4); p("filetype_"nfiles, "PDF"); }
    /^[!]*pcl/    { p("files_"++nfiles, $4); p("filetype_"nfiles, "PCL"); }
    /^page:/    { p("pins_"++npins, $4); }
    /^data:/    { p("files_"++nfiles, $4); }
    /^poll/        { p("poll", " -p"); }
    END { p("nfiles", nfiles); p("npins", npins) } ' $QFILE `
    eval "$AWK_OUTPUT"
}

#
# Produce faxable TIFF (MH, MR, MMR) from a PDF or Postscript file.
#
gs2fax()
{
    test -z "$files" && files="-"	# read from stdin
    case "${pagewidth}x${pagelength}" in
	1728x280|1728x279|2592x280|2592x279|3456x280|3456x279)	# 279.4mm is actually correct...
	    paper=letter;;
	1728x364|2592x364|3456x364) 
	    paper=legal;;
	*x296|*x297)			# more roundoff problems...
	    paper=a4;;
	*x364)
	    paper=b4;;
	2432x*|3648x*|4864x*)
	    paper=a3;;
	*)
	    echo "$0: Unsupported page size: $pagewidth x $pagelength";
	    exit 254;;			# causes document to be rejected
    esac
    #
    # The image must end up with a pixel width according to T.32 Table 21.
    # Ghostscript contains code to fixate a4 and letter to 1728 pixels
    # when using 196-204 dpi and tiffg3/4, it supposedly does the same for
    # B4 but not for A3, thus the floats are needed (for A3's benefit).
    #
    # See ghostscript/doc/Devices.htm under -dAdjustWidth=1 (default).
    # Use -dAdjustWidth=0 to disable.  With the right patch,
    # http://bugs.ghostscript.com/show_bug.cgi?id=688064
    # AdjustWidth can be made to specify the pagewidth directly and
    # replace -dFIXEDMEDIA to permit TIFFs to be produced with
    # varied lengths.
    #
    # Another alternative to -dFIXEDMEDIA is -dPDFFitPage which has the 
    # difference of "resizing" images to fit the page rather than cutting
    # them off.
    #
    case "$paper" in
	a4)
	    case "$pagewidth" in
		2592) hres=313.65;;		# VR_300X300
		3456) hres=418.20;;		# VR_R16
		*) hres=209.10;;		# everything else, 1728 pixels
	    esac;;
	b4)
	    case "$pagewidth" in
		3072) hres=311.97;;		# VR_300X300
		4096) hres=415.95;;		# VR_R16
		*) hres=207.98;;		# everything else, 2048 pixels
	    esac;;
	a3)
	    case "$pagewidth" in
		3648) hres=311.94;;		# VR_300X300
		4864) hres=415.93;;		# VR_R16
		*) hres=207.96;;		# everything else, 2432 pixels
	    esac;;
	*)					# letter, legal
	    case "$pagewidth" in
		2592) hres=304.94;;		# VR_300X300
		3456) hres=406.59;;		# VR_R16
		*) hres=203.29;;		# everything else, 1728 pixels
	    esac;;
    esac

    #
    # The sed work fixes bug in Windows-generated
    # PostScript that causes certain international
    # character marks to be placed incorrectly.
    #
    #    | $SED -e 's/yAscent Ascent def/yAscent 0 def/g' \
    #
    # NB: unfortunately it appears to break valid PostScript;
    #     so it's been disabled.

    #
    # Suggestion from "Alan Sparks" <asparks@nss.harris.com>,
    # Add the -DFIXEDMEDIA argument to the last command in ps2fax.
    # This prevents page sizing within the documents from altering
    # the command-line page size specification.  This prevents
    # TIFFs to be made with pages of varied lengths, however.
    # See the comments on AdjustWidth above.
    #
    FIXEDWIDTH="-dFIXEDMEDIA"

    #
    # Ghostscript's default dithering with the fax drivers is 
    # usually unsatisfactory.  So we have an option to process
    # the image through libtiff's Floyd-Steinberg dithering.
    # This will be a bit more costly on CPU and image preparation
    # time... enable it cautiously.
    #
    # An alternative to libtiff Floyd-Steinberg dithering would
    # be to use a threshold array based stochastic mask within
    # Ghostscript.  However, this alternative may perform less 
    # than ideally on unmodified Ghostscript versions prior to 8.62.
    # See: http://bugs.ghostscript.com/show_bug.cgi?id=689633
    #
    DITHERING=default

    #
    # Apply customizations such as watermarking.
    #
    if [ -f etc/FaxModify ]; then
	. etc/FaxModify
    fi

    if [ "$DITHERING" = "gs-stocht" ]; then
	$CAT $files | $PS -q \
	    -sDEVICE=$device \
	    -dNOPAUSE \
	    -dSAFER=true \
	    -sPAPERSIZE=$paper \
	    $FIXEDWIDTH \
	    -dBATCH \
	    -r$hres\x$vres \
	    "-sOutputFile=$out" \
	    stocht.ps -c "<< /HalftoneMode 1 >> setuserparams" -
	return
    fi
    if [ "$DITHERING" = "libtiff-fs" ] && ($PS -h | grep tiff24nc >/dev/null 2>&1) && \
       [ -x $TIFFBIN/tiff2bw ] && [ -x $TIFFBIN/tiffdither ] && [ -x $TIFFBIN/tiff2ps ] && \
       [ -x $TIFFBIN/tiffsplit ] && [ -x $TIFFBIN/tiffcp ]; then
	$PS -q -sDEVICE=tiff24nc -dNOPAUSE -dSAFER=true -sPAPERSIZE=$paper \
	    $FIXEDWIDTH -dBATCH -r$hres\x$vres "-sOutputFile=$out.1" $files
	# Both tiff2bw and tiffdither only operate on single pages, so...
	mkdir tmpdir.$$
	cd tmpdir.$$
	$TIFFBIN/tiffsplit ../$out.1
	for i in *; do
	    $TIFFBIN/tiff2bw $i $i.2
	    $TIFFBIN/tiffdither $i.2 $i.3
	    $RM -f $i $i.2
	done
	$TIFFBIN/tiffcp * ../$out.2
	$RM -f *
	cd ..
	rmdir tmpdir.$$
	#
	# Unfortunately, this process leaves the image with Photometric of min-is-black, which
	# is opposite from what we need for faxing.  So we have to run it again through gs.
	#
	$TIFFBIN/tiff2ps -a $out.2 > $out.3
	files=$out.3
    else
	DITHERING=default
    fi

    $PS -q \
	-sDEVICE=$device \
	-dNOPAUSE \
	-dSAFER=true \
	-sPAPERSIZE=$paper \
	$FIXEDWIDTH \
	-dBATCH \
	-r$hres\x$vres \
	"-sOutputFile=$out" \
	$files

    if [ "$DITHERING" = "libtiff-fs" ]; then
	$RM -f $out.1 $out.2 $out.3
    fi
}
