[comp.sources.unix] v24i040: Email fax-sending package, Part02/05

rsalz@uunet.uu.net (Rich Salz) (03/14/91)

Submitted-by: klaus u schallhorn <cnix!klaus>
Posting-number: Volume 24, Issue 40
Archive-name: faxpax/part02

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# Contents:  FaxConfig faxhost/faxfonts/diykit.c faxhost/sendfax.c
# Wrapped by rsalz@litchi.bbn.com on Wed Mar 13 14:08:01 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive 2 (of 5)."'
if test -f 'FaxConfig' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'FaxConfig'\"
else
  echo shar: Extracting \"'FaxConfig'\" \(25531 characters\)
  sed "s/^X//" >'FaxConfig' <<'END_OF_FILE'
X#!/bin/sh
X#
X# $Header: FaxConfig, 2.2.91, ks
X# basically a [very much] stripped down and ripped off version of rn/Configure
X# where it says:
X# Yes, you may rip this off to use in other distribution packages.
X# so I did
X
Xn=''
Xc=''
Xcontains=''
X
Xmodemtypes='1'
X
Xcharset='i'
Xdevice="/dev/not_that_one"
Xdevlock="LCK..nosuchdevice"
Xdialstr=""
Xdialtype='T'
Xnet='y'
Xnetwide_fax="NETWIDE_FAX"
Xfaxhost="faxhost"
Xfaxadmin=`whoami`
Xfaxadmin="$faxadmin@"`hostname`
Xfaxfmode='0644'
Xfaxlib='/usr/local/lib/faxlib'
Xfaxspool='/usr/local/spool/fax'
Xfmtype="sierra"
Xlocalbin='/usr/local/bin'
Xloglevel='9'
Xmanshelf='/usr/share/man'
Xmaxresend='3'
Xmaxage='1'
Xmaxtry='5'
Xtopspeed='7'
Xuucplocks='/var/spool/locks'
X
X
Xecho "Beginning of configuration questions for faxpak."
Xecho " "
X
X: some greps do not return status, grrr.
Xecho "grimblepritz" >grimble
Xif grep blurfldyick grimble >/dev/null 2>&1 ; then
X    contains=contains
Xelse
X    if grep grimblepritz grimble >/dev/null 2>&1 ; then
X	contains=grep
X    else
X	contains=contains
X    fi
Xfi
X
X: sanity checks
XPATH='.:/bin:/usr/bin:/usr/local/bin:/usr/ucb:/usr/local:/usr/lbin:/etc'
Xexport PATH || (echo "OOPS, this isn't sh.  Desperation time.  I will feed myself to sh."; sh $0; kill $$)
X
Xif test ! -t 0; then
X    echo "Type 'sh FaxConfig', not 'sh <FaxConfig'"
X    exit 1
Xfi
X
X: first determine how to suppress newline on echo command
Xecho "Checking echo to see how to suppress newlines..."
X(echo "hi there\c" ; echo " ") >.echotmp
Xif $contains c .echotmp >/dev/null 2>&1 ; then
X    echo "...using -n."
X    n='-n'
X    c=''
Xelse
X    echo "...using \\\c."
X    n=''
X    c='\c'
Xfi
Xecho $n "Type carriage return to continue.  Your cursor should be here-->$c"
Xread ans
Xrm .echotmp
X
X: now set up to do reads with possible shell escape
X: if this does not work on your machine, 1,$s/. myread/read ans/
Xcat <<EOSC >myread
Xans='!'
Xwhile expr "X\$ans" : "X!" >/dev/null; do
X    read ans
X    case "\$ans" in
X    !)
X	sh
X	echo " "
X	echo $n "Your answer: $c"
X	;;
X    !*)
X	set \`expr "X\$ans" : "X!\(.*\)\$"\`
X	sh -c "\$*"
X	echo " "
X	echo $n "Your answer: $c"
X	;;
X    esac
Xdone
XEOSC
X
X
Xcat <<EOT
X 
X# general info
X##############################################################################
XThis installation shell script asks you some questions regarding the
Xsetup of faxpak. Currently there is no support for hardware other than
XSun Microsystems'. To port this to other machines run this script 
Xanyway, but then have a close look at wiring.c. Wiring.c can be used
Xas a standalone test program with TESTING defined, and with TEST_DEVICE
Xdefined to a port you can use for testing [you can reconfig any time],
Xpreferably without interfering logins.
X
XThis script builds a header file faxconfig.h, a soft configuration file
Xfax,config, fax.1 man pages and, if you're lucky, two faxpak fonts.
X
XDefault answers are shown in [brackets]. Hitting carriage return accepts
Xthe defaults. Once you have faxconfig.h and fax.config you can change
Xeach file by editing it without re-running this script.
X
XEOT
X
Xecho $n "[Type carriage return to continue] $c"
X. myread
Xecho " "
X
X
Xcat <<EOT
X
X##############################################################################
Xfaxpak can run on networked and standalone machines.
X
XIf faxpak is networked, it is assumed that one HOST has the faxmodem[s],
Xwith all other machines acting as CLIENTS, spooling outgoing fax jobs to
Xthe faxhost.
X
XThe faxhosts' duty is to convert incoming text files into group 3 fax files,
Xand to do the actual transmission, to log what's going on, to report by
Xmail [if requested] and to do house keeping chores. This is done by entries
Xin root's crontab which calls sendfax frequently and faxcleanup once a day.
X
XEOT
X
Xdflt=$net
Xecho $n "Do you expect to run faxpak on networked machines? [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
X
X
Xif [ $ans = y ]
Xthen
X
X	cat <<EOT
X
X# network info, don't really need much
X######################################################################
X"client" machines find the faxhost by calling gethostbyname(FAXHOST),
Xwith FAXHOST #defined in faxconfig.h on our sita as "faxhost",
Xand with "faxhost" aliased in /etc/hosts to mbox. mbox is a 3/60 that
Xacts as our spooling machine [printing, faxing, mail, news archive etc.].
X
XEOT
X
X	dflt=$faxhost
X	echo "Please enter the \"synonym\" your FAXHOST will be known by -"
X	echo $n "[I guess you could enter the name of a known machine]: [$dflt] $c"
X	. myread
X	echo
X	case $ans in
X	'') ans=$dflt;;
X	esac
X	faxhost=$ans
Xelse
X	net='n'
X	netwide_fax="nonet"
Xfi
X
X
Xcat <<EOT
X
X# we need someone to blame when things go wrong
X##############################################################################
XThe bad news is that things DO go wrong. Therefore we may need 
Xsomeone to interfere by hand, or to lend a hand if a user needs help,
Xor to give the default answer ["You can't to that"].
X
XEOT
Xdflt=$faxadmin
Xecho $n "Name a patient person suitable for dealing with fax problems: [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xfaxadmin=$ans
X
X
X# what arg do we give chmod()
X##############################################################################
Xdflt=$faxfmode
Xecho $n "Please enter the file access perms to be enforced by faxpak: [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xfaxfmode=$ans
X
Xcat <<EOT
X
X
X# where to put faxlib and the spool dir
X##############################################################################
XTo keep things somewhat organised we need to define a /someplace/faxlib,
Xand a /somewhere/spooldir for faxpak. I prefer to keep them separate from
Xdistribution libs and spool dirs. I'd also like to know where you keep you
Xman pages.
X
XEOT
Xdflt=$faxlib
Xecho $n "Please enter the path to faxlib: [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xfaxlib=$ans
X
X
Xdflt=$faxspool
Xecho $n "And path to faxspool: [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xfaxspool=$ans
X
X
Xdflt=$manshelf
Xecho $n "And your Manual Shelf: [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xmanshelf=$ans
X
Xcat <<EOT
X
X# find competing uucp locks
X##############################################################################
XModem logins, uucp transmissions and faxes all the same time and on
Xthe same modem tend become somewhat garbled. Tell me where uucp keeps
Xits lock files, so that sendfax dies away instantly if uucp is active
X[it knows about logins on a port].
X
XEOT
Xdflt=$uucplocks
Xecho $n "Where does uucp create its lock files: [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xuucplocks=$ans
X
X
Xcat <<EOT
X
X# local bin for fax
X##############################################################################
XAssuming you don't put local executables into /usr/{bin,ucb}, we need
Xsort of a /local/bin to put the user interface [called fax] into.
X
XEOT
Xdflt=$localbin
Xecho $n "Where do you keep local executables: [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xlocalbin=$ans
X
X
Xcat <<EOT
X
X# max no of resends within one transmission
X##############################################################################
XThe last hard wired bit of info is the number of resends. If a page is
Xgarbled during transmission, the two hardware gizzmos, that is your
Xfaxmodem on this side and the fax machine on the other end, can agree
Xto resend that page. I don't know if fax machines have a built in limit
Xfor the number of resent pages, I do, however, feel safer if I know
Xsendfax doesn't spend all night resending a page. Having seen the different
Xlevels of compliance to the CCITT specs, especially european fax machines',
XI would doubt, if such a limit is enforced.
X
XEOT
Xdflt=$maxresend
Xecho $n "How often do you permit the resending of a page within one call [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xmaxresend=$ans
X
X
X# have header info, get details for fax.config
X##############################################################################
X
Xif [ $modemtypes = 2 ]
Xthen
X	mtypestring="faxmodem type, currently class2 and sierra type modems are supported"
Xelse
X	mtypestring="faxmodem type, currently only sierra type modems are supported"
Xfi
X
Xcat <<EOT
X
X# soft configuration, saved in $faxlib/fax.config"
X##############################################################################
XMost of the configuration of faxpak can be changed after compiling faxpak.
XSoftwired details are stashed into $faxlib/fax.config, allowing for easy 
Xalteration once you have faxpak working. The fax.config file stores:
X
X1: the ports to which you have faxmodems connected *)
X2: literal name of lockfile for each port, in case uucp uses these ports
X   as well as faxpak *)
X3: $mtypestring
X4: Tone or Pulse dialling
X5: Highest speed your faxmodems are capable of [RTFFaxmodemM]
X6: an optinal string to re-enable dialins on the port after sendfax is done,
X   see /etc/uucp/Dialers, or the modem docs, for examples
X
X7: wildcarded dialcodes and times, faxes to these area codes are ok *)
X
X8: max no of days a fax is allowed to sit in $faxspool
X9: max no of attempts to send a fax
X
Xlog level, 9 logs everything [huge!], 0 only some relevant info
X
XFaxConfig only writes a preliminary file including some comments. Feel
Xfree to edit it to your liking at any time.
X
X*) these are best done with an editor, in fact, I don't even ask for
X   dialcode:time pairs. see the file fax.config when done with this script.
X   [you could also call this load sharing between you and me].
X
XEOT
X
Xdflt=$device
Xecho $n "Please enter the first port to be used [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xdevice=$ans
X
Xdflt=$devlock
Xecho "Please enter lockname to block uucp while we're"
Xecho $n "sending out faxes [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xdevlock=$ans
X
Xif [ $modemtypes = 2 ]
Xthen
X	dflt=$fmtype
X	echo $n "Please enter modem type [$dflt] $c"
X	. myread
X	echo
X	case $ans in
X	'') ans=$dflt;;
X	esac
X	fmtype=$ans
Xfi
X
Xdflt=$dialtype
Xecho $n "Please enter 'P' if you want pulse dialling [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xdialtype=$ans
X
Xdflt=$topspeed
Xecho "Please enter code for highest baud rate your modem can "
Xecho $n "fax at - see modem manual [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xtopspeed=$ans
X
Xdflt=$dialstring
Xecho "If you feel brave enough [else leave blank and do later]"
Xecho $n "String to reenable dialins on ports used by faxmodems [$dflt] $c"
X. myread
Xecho
X
Xdflt=$maxage
Xecho $n "How many days is a fax allowed to sit in the queue [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xmaxage=$ans
X
Xdflt=$maxage
Xecho $n "How many attempts do you allow to connect to one phone no [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xmaxtry=$ans
X
Xdflt=$loglevel
Xecho $n "What log level do you want sendfax [wiring for testing] to log at [$dflt] $c"
X. myread
Xecho
Xcase $ans in
X'') ans=$dflt;;
Xesac
Xloglevel=$ans
X
X
X
Xcat <<EOT
X
X# charset info
X##############################################################################
XAlthough I planned to support quite a few different character sets [with
Xthe help of several netters] faxpak currently supports the following few. 
XFor those poor souls whose expression is limited to 7 bits, the decision
Xmust be based on rand().
X
XPlease enter the charset you want faxpak to use:
X
X	i	iso 8859.1
X	p	pc de facto [code page 850] standard *)
X	8	pc code page 861
X
X*) Some people felt strongly the ibm pc code page 850 is NOT a de facto
X   standard. IMHO it is insofar as the uk, germany, switzerland and some
X   other mid european countries are concerned, where quite a chunk of 
X   "the action" takes place. If you still disagree, don't use faxpak.
X
XEOT
X
Xdflt=$charset
Xecho $n "What charset do you want to use [$dflt] $c"
X. myread
Xecho
Xecho	copying font definition for diy font kit
Xcase $ans in
X'p')	cp faxhost/faxfonts/diy_ibmpc.def faxhost/faxfonts/diykit.def;;
X'8')	cp faxhost/faxfonts/diy_codep861.def faxhost/faxfonts/diykit.def;;
X*)	cp faxhost/faxfonts/diy_iso.def faxhost/faxfonts/diykit.def;;
Xesac
X
Xrm -f myread grimble
X
X
X# have fax.config, write faxconfig.h and fax.config
X###################################################
X
Xecho	"writing faxconfig.h"
X
Xcat	>faxconfig.h <<EOT
X
X/*
X	fax configuration header [faxconfig.h],
X	shared by faxclient/fax.c, and faxhost/*.c
X
X	Copyright (C) 1991, klaus schallhorn, klaus@cnix.uucp
X
X	Permission to use, copy, modify, and distribute this software 
X	and its documentation for any purpose and without fee is hereby 
X	granted, provided that the above copyright notice appear in 
X	all copies and that both that copyright notice and this permission 
X	notice appear in supporting documentation. 
X
X	This software is provided "as is" without express or implied warranty.
X*/
X
X#define	$netwide_fax
X
X
X			/* some common bits 'n pieces */
X#ifndef	TRUE
X#define	TRUE		1
X#define	FALSE		0
X#define	ERROR		(-1)
X#endif
X
X#ifndef	min
X#define	min(a,b)	((a<b)?a:b)
X#define	max(a,b)	((a>b)?a:b)
X#endif
X
X
X			/* network stuff */
X#ifdef	NETWIDE_FAX
X#define	FAXHOST		"$faxhost"		/* get host by name */
X#endif
X
X
X			/* application specific stuff */
X#define	FAXADMIN	"$faxadmin"		/* mail errors if !user */
X#define	FAXFMODE	$faxfmode			/* for chmod */
X#define	FAXSERVER	"spool.fax"		/* name of spool pgm */
X#define	FAXLIB		"$faxlib"	/* needed on faxhost only */
X#define	FAXSPOOL	"$faxspool"	/* needed on faxhost only */
X
X#define	UUCPLOCKS	"$uucplocks"	/* again host only */
X#define	LOCALBIN	"$localbin"		/* client && host, for fax.c */
X
X#define	MAX_RESEND	$maxresend			/* don't resend a page forever */
X#define	FAXLFONT	"textfaxl.font"		/* lores bitmap font from diykit */
X#define	FAXHFONT	"textfaxh.font"		/* hires bitmap font from diykit */
X#define	PSFONT		"Courier-Bold12"	/* ghostscript font */
X
X#define	MAX_FAX_LINES	2400		/* is a bit generous, so what */
X
X#define	COARSE		1		/* 204.15 by 97.79 dpi */
X#define	FINE		2		/* 204.15 by 195.58 dpi */
X#define	HP		3
X
X#define	ASCII		0	/* use hp laser jet compat font to create pbm */
X#define	PBM		1	/* use as is, sort of */
X			/* these aren't done yet, see wiring.c, why */
X#define	DVI		2	/* dvi2ps, NOT YET DONE */
X#define	GHOSTSCRIPT	3	/* ideas [not yet] stolen from mit ai labs */
X#define	HPCL		4	/* hp laser jet compat output */
X
X
X			/* fax modem specific bits */
X#define	BETA_FIRMWARE		/* applies to wiring.c */
X#define	SIERRA			/* type of fax modem */
X
X
X#ifdef	NEED_FAXTYPES		/* needed in fax.c and spool.fax.c */
Xstruct	ftypes
X{
X	char	*typename;
X	int	typeid;
X} faxtypes[] =
X{
X	"ascii",	ASCII,
X	"pbm",		PBM,
X	"dvi",		DVI,
X	"postscript",	GHOSTSCRIPT,
X	"hpcl"		HPCL
X};
X#define	MAX_FTYPE	sizeof(faxtypes)/sizeof(struct ftypes)
X#endif	/* need fax types */
X
X
Xstruct FAX
X{
X	long	spooled;
X	char	user[80];
X#ifdef	JOBID
X	char	jobid[80];
X#endif
X	char	dname[256];
X	char	xname[256];
X	char	**phone;
X	int	tries,
X		hires,
X		uid,
X		now,
X		mail,
X		pages,
X		type,
X		phone_nos;
X	long	tpos,
X		ppos;
X};
XEOT
X
Xecho	"writing fax.config"
X
Xcat	>fax.config <<EOT
X# fax.config
X# Copyright (C) 1991 klaus schallhorn, klaus@cnix.uucp
X#
X# Permission to use, copy, modify, and distribute this software 
X# and its documentation for any purpose and without fee is hereby 
X# granted, provided that the above copyright notice appear in 
X# all copies and that both that copyright notice and this permission 
X# notice appear in supporting documentation. 
X#
X# This software is provided "as is" without express or implied warranty.
X#
X#
X# fax devices
X# ===========
X# 2nd column contains the actual device for sendfax
X# ie /dev/cua1
X#
X# 3rd col states lock name to be used so that uucp does not even try 
X# to interfere while we're faxing. Stating the lock name verbatim is 
X# essential since there are differences between HDB uucp and older/other 
X# versions.
X# NOTE: if you don't share faxmodems with uucp, locknames don't really 
X# matter as long as each port has a distinctive lockname. fred1, fred2 
X# ... fredn would be acceptable.
X#
X# 4th col specifies the modem type connected to that port so sendfax knows 
X# how to talk to the hardware.
X#
X# 5th col is either T [as in tone dialling] or P [pulse].
X#
X# 6th col is highest speed you want to connect at, see your modem manual.
X#
X# 7th col is a string sent to the fax modem AFTER we've used it IF you 
X# want to enable incoming calls/getty, for a typical string see 
X# /etc/uucp/Diallers, string has to be "in quotes", absence of a string 
X# implies nothing to send.
X#
X# this is what fax.config looks here
X# 1st	2nd	    3rd	        4th      5th 6th 7th
X#device	/dev/cua1   LCK..cua1   sierra     T   7 "ATE1M0V1X1Q0S2=127S0=4S12=255"
X#device	/dev/cua2   LCK..cua2   sierra     T   7 "ATE1M0V1X1Q0S2=127S0=4S12=255"
Xdevice	$device	$devlock	$fmtype	$dialtype	$topspeed	$dialstr
X#
X#
X# phone bill saver
X# ================
X#
X# I do not want faxes at peak rates, except local ones.
X#
X# long distance call phone nos start with a zero PLUS any combination of 
X# digits 1 to 9 [1-9][1-9]* 
X# NOTE: no zeros in 2nd or 3rd digit, except if 2nd digit > 1
X#
X# international ones start with 010 cty code PLUS any combination of 1 to 9
X#
X# This feature can be raped to make sure faxes to specific fax numbers 
X# are only sent at an acceptable [for the recipient] time, as shown in the 
X# first "hour entry". Hard coded phone nos should come before wild card 
X# entries.
X#
X# This sample states that long distance is ok from 6 pm to 6 am, 
X# international ones from 8 pm to 6 am
X#
X#hours	0104977777777	9 - 12	# this guy can only be sent to in the morning
X#hours	01049123456	8 - 10 14 16 - 19 
X#hours	0[1-9][1-9]*	18 - 6	# as in 078 123 6789
X#hours	0[2-9]*		18 - 6	# as in 030 455 6748
X#hours	010[1-9]*	20 - 6	# as in 01049 30 345 6789
X#
X#
X# max age of files in spool dir [days], fax is supposed to be fast!
X# =============================
X#
Xmaxage	$maxage
X#
X#
X# max number of attempts to connect
X# =================================
X#
Xmaxtry	$maxtry
X#
X# log level
X# =========
X#
X# 9 = everything
X# 0 = errors, transmission times
X# other useful levels are 3 and 5
X#
Xloglevel $loglevel
X#
X#
X# end of fax.config
XEOT
X
X# now save fax.1 man pages
X##########################
X
Xecho	"writing faxclient/fax.1 man pages"
X
Xcat	>faxclient/fax.1 <<EOT
X.TH fax 1 "Feb 4th, 1991"
X.SH NAME
Xfax \- send a Group 3 fax via faxmodem.
X.SH SYNOPSIS
Xfax phone_no [-a -f -h -l -m -n -r -s] file
X.SH DESCRIPTION
XFax accepts ascii input and sends it as a group 3 fax
Xusing a sierra type faxmodem. The first parameter is either
Xa phone number, an alias [see aliases] or a distribution list [see lists] 
Xfile name.
X.sp
XIf the first parameter contains digits only, it is
Xassumed to be a phone number.
X.sp
XIf your site does enforce permissions, you may have to ask your
Xadministrator [$faxadmin] for permission to fax.
X.SH PARAMETERS
X.TP
X.B -a'for the attention of...'
XTo specify a recipient within an organization for internal
Xrouting. The string must be quoted so it's passed as one
Xargument to fax. It is then prepended to the outgoing message.
X.TP
X.B -f/absolute/font/path/fontfile
XUse an alternative font. In addition to the default typewriter fonts
Xin low and high resolution fax knows about 
XHP Laserjet compatible fonts [up to 30 points in height]. These are
Xscaled to the resolution of the outgoing fax. Used with low resolution
Xthe output is not pretty.
X.TP
X.B -h
XUse high resolution mode [204 by 195 dots per inch]. This almost doubles
Xthe transmission time.
X.TP
X.B -l
XUse low resolution mode [204 by 97 dots per inch].
X.TP
X.B -m
XReport by mail as soon as the fax has been sent. Fatal errors or failure
Xto deliver is reported back irrespectible of the mail flag setting.
X.TP
X.B -n
XSend the fax "now" rather than at cheap rate, where "now" refers
Xto the next time the fax daemon runs. To bypass the time restrictions [if
Xany] you may need to have special permission.
X.TP
X.B -r'return fax number string'
XThis string is prepended to the outgoing fax to specify a return
Xfax number. Currently fax does not support incoming faxes.
X.TP
X.B -s
XSave outgoing faxes in HOME/Fax.Sent/phone.date. Fax saves outgoing faxes in
Xfiles whose name is a concatenation of recipient and date. If the recipient
Xis not an alias and not a distribution list, the phone number is
Xused for the first part of the file name.
X.PP
XFile is an ascii file containing a formatted message.
X.SH DEFAULTS
XYou can override built in defaults by creating a file ".faxrc" in
Xyour home directory. This file is consulted before fax reads 
Xcommand line parameters.
X.sp
XPermitted default values in .faxrc are those that apply to
Xall outgoing faxes sent by one user. Command line option override
Xthese dafaults, however.
X.TP
X.B font
XThe name of a font to be used by fax. The font has to be available
Xon the machine running the fax daemon. The fontfile
Xmust be accessible to the fax daemon.
X.TP
X.B resolution
XCan be high or low [see above]. Default: low. 
X.TP
X.B mail
XSet to yes for notification by mail. Default: no.
X.TP
X.B now
XSet to yes for sending next time the fax queue is checked
Xfor outgoing faxes. Default: no.
X.TP
X.B retfax
XA string to be prepended all your outgoing faxes. No default string.
X.TP
X.B save
XIf set, saves files in HOME/Fax.Sent/phone.date. Default: no.
X.SH ALIASES
XIf the first parameter to fax contains alphabetic characters, fax first
Xchecks your HOME directory for a file fax.aliases. This file contains
Xa list of names, phone numbers, optionally ftao [for the attention of] 
Xstrings to be prepended to each outgoing fax. Anything appearing after a # 
Xsign is treated as a comment.
X.sp
XA sample fax.aliases file might look:
X.sp
X.nf
Xfred	12345678	:For the attn of Fred Bloggs 	# comment
Xbill	98765
Xsue	765432389	:The Lady in Pink 			# another comment
X.fi
X.SH LISTS
XIf an alias is not found in fax.aliases, fax tries to open a distribution
Xlist with the same name. Distribution lists are similar to alias files.
XA sample distribution list might look:
X.sp
X.nf
X12345678	:For the attn of Fred Bloggs 	# comment
X98765
X765432389	:The Lady in Pink 			# another comment
X.fi
X.SH INTERACTIVE USE
XIf fax is not given a file name on the command line, it reads 
Xit's standard input until a line starting with a '.' is encountered,
Xor until EOF.
X.sp
XEntering of a fax can be aborted by hitting ^C. Entering ~v at the beginning of
Xa line calls the default editor, if specified by the environment variable
XEDITOR, or /usr/ucb/vi.
X.sp
XStarting a line with ~p prints the message entered to far.
X.SH AUTHOR
XKlaus Schallhorn
X.SH COPYRIGHT
XCopyright (C) 1991 Klaus Schallhorn, klaus@cnix.uucp
X.sp
XPermission to use, copy, modify, and distribute this software and its
Xdocumentation for any purpose and without fee is hereby granted, provided
Xthat the above copyright notice appear in all copies and that both that
Xcopyright notice and this permission notice appear in supporting
Xdocumentation.  This software is provided "as is" without express or
Ximplied warranty.
XEOT
X
Xecho	"writing Makefiles"
X
Xcat	>Makefile <<EOT
X# Makefile for faxpak
X#
X# Copyright (C) 1991 klaus schallhorn, klaus@cnix.uucp
X#
XCC =		cc
XCFLAGS =	-O2
XLDFLAGS =	-s
X
XFAXLIB =	$faxlib
XFAXFMODE =	$faxfmode
XLOCALBIN =	$localbin
XMANSHELF =	$manshelf
X
XSHELL =		/bin/sh
X
XSUBS =		faxclient faxhost faxhost/faxfonts
X
X
Xall:
X	for i in \$(SUBS) ; do \
X		( cd \$\$i ; make \$(MFLAGS) 'CC=\$(CC)' 'CFLAGS=\$(CFLAGS)' 'LDFLAGS=\$(LDFLAGS)' all ); \
X	done
X
Xinstall:
X	for i in \$(SUBS) ; do \
X		( cd \$\$i ; make \$(MFLAGS) 'LOCALBIN=\$(LOCALBIN)' 'MANSHELF=\$(MANSHELF)' 'FAXLIB=\$(FAXLIB)' 'FAXFMODE=\$(FAXFMODE)' install ); \
X	done
X
Xclean:
X	-rm -f Part?? *.hdr fax.config
X	for i in \$(SUBS) ; do \
X	    ( cd \$\$i ; make \$(MFLAGS) clean ); \
X	done
X
XEOT
X
Xcat	>faxclient/Makefile <<EOT
X# Makefile for faxclient
X
Xall:		fax
X
Xfax:		fax.o
X		cc -o fax \$(LDFLAGS) fax.o
X
Xfax.o:		fax.c
X		cc \$(CFLAGS) -c fax.c
X
Xinstall:	bininstall maninstall
X
Xbininstall:	fax
X		cp fax \$(LOCALBIN)
X
Xmaninstall:	fax.1
X		cp fax.1 \$(MANSHELF)/man1
X		chmod 644 \$(MANSHELF)/man1/fax.1
Xclean:
X		-rm -f *.o *.a core fax
X
XEOT
X
Xcat	>faxhost/Makefile <<EOT
X# Makefile for faxhost
X
XFAXCLEANUP =	faxcleanup.o faxlog.o
XSENDFAX =	sendfax.o wiring.o faxlog.o
XSPOOLFAX =	spool.fax.o faxlog.o
XTEXTTOPBM =	texttopbm.o fntwrite.o
XFAXHDR =	../faxconfig.h
X
XPGMS =		faxcleanup sendfax spool.fax texttopbm
XTEXTFILES =	fax.config textfaxl.font textfaxh.font
X
Xall:		\$(PGMS)
X
Xfaxcleanup:	\$(FAXHDR) \$(FAXCLEANUP)
X		cc -o faxcleanup \$(LDFLAGS) \$(FAXCLEANUP)
X
Xsendfax:	\$(FAXHDR) sierracmd.h \$(SENDFAX)
X		cc -o sendfax \$(LDFLAGS) \$(SENDFAX)
X
Xspool.fax:	\$(FAXHDR) \$(SPOOLFAX)
X		cc -o spool.fax \$(LDFLAGS) \$(SPOOLFAX)
X
Xtexttopbm:	\$(FAXHDR) \$(TEXTTOPBM)
X		cc -o texttopbm \$(LDFLAGS) \$(TEXTTOPBM)
X
Xinstall:
X		cp \$(PGMS) \$(FAXLIB)
X		cp ../fax.config \$(FAXLIB)
X		for i in \$(TEXTFILES) ; do \
X			( chmod \$(FAXFMODE) \$(FAXLIB)/\$\$i ); \
X		done
X		for i in \$(PGMS) ; do \
X			( chmod 0500 \$(FAXLIB)/\$\$i ); \
X		done
X		chmod 6711 \$(FAXLIB)/spool.fax
X		chown root.daemon \$(FAXLIB)/*
X
Xclean:
X		-rm -f *.o *.a core \$(PGMS)
X
XEOT
X
Xcat	>faxhost/faxfonts/Makefile <<EOT
X# Makefile for faxhost/faxfonts
X
X# path for textfax?.font is hardwired into diykit [in ../../faxconfig.h]
Xall:		diykit lores.data hires.data \
X			$faxlib/textfaxl.font $faxlib/textfaxh.font
X
Xdiykit:		diykit.o
X		cc -o diykit \$(LDFLAGS) diykit.o
X
Xdiykit.o:	../../faxconfig.h diykit.h diykit.c
X		cc \$(CFLAGS) -c diykit.c
X
X# path for textfax?.font is hardwired into diykit [in ../../faxconfig.h]
X$faxlib/textfaxl.font: lores.data
X		./diykit
X
X$faxlib/textfaxh.font: hires.data
X		./diykit
X
Xlores.data:	lores.uue
X		uudecode lores.uue && uncompress lores.data.Z
X
Xhires.data:	hires.uue
X		uudecode hires.uue && uncompress hires.data.Z
X
X
Xinstall:
X
Xclean:
X		-rm -f *.o *.a *.data core diykit
X
XEOT
X
X# end of FaxConfig
END_OF_FILE
  if test 25531 -ne `wc -c <'FaxConfig'`; then
    echo shar: \"'FaxConfig'\" unpacked with wrong size!
  fi
  # end of 'FaxConfig'
fi
if test -f 'faxhost/faxfonts/diykit.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'faxhost/faxfonts/diykit.c'\"
else
  echo shar: Extracting \"'faxhost/faxfonts/diykit.c'\" \(5399 characters\)
  sed "s/^X//" >'faxhost/faxfonts/diykit.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <malloc.h>
X#include <ctype.h>
X#include "diykit.h"
X
X#include "../../faxconfig.h"
X
Xstatic	char *PGM = "diykit";
Xchar	charset[128];
Xint	bm_len;
Xextern	int errno;
X
Xstruct	FNT_BITMAP	/* one for each char */
X{
X	short *SH;
X	short active;
X} font[256];
X
X
Xfont_init(name)
Xchar *name;
X{
X	FILE *hp;
X	int i;
X	struct FNT_BITMAP *cf;
X	static int fst;
X	char tmp[4];
X
X	errno = 0;
X	if (!fst)
X		for (i=0; i<256; i++)	/* just to be safe */
X		{
X			cf = &font[i];
X			cf->SH = (short *)NULL;
X			cf->active = 0;
X		}
X	else for (i=0; i<256; i++)	/* just to be safe */
X		{
X			cf = &font[i];
X			if (cf->SH)
X				free(cf->SH);
X			cf->SH = (short *)NULL;
X			cf->active = 0;
X		}
X
X	if ((hp = fopen(name, "r")) == NULL)
X	{
X		fprintf(stderr,"%s: can't open %s font, errno %d\n",PGM,name,errno);
X		return(ERROR);
X	}
X
X	if (fread(tmp, sizeof(char), 3, hp) != 3)
X	{
X		fprintf(stderr,"%s: can't read fontfile %s, errno %d\n",PGM,name,errno);
X		return(ERROR);
X	}
X	if (!strncmp(tmp, "fxL", 3))
X		bm_len = 16;
X	else if (!strncmp(tmp, "fxH", 3))
X		bm_len = 32;
X	else
X	{
X		fprintf(stderr,"%s: %s is not a bitmap font\n",PGM,name);
X		return(ERROR);
X	}
X
X	if (rd_diykit(hp))
X		return(ERROR);
X
X	fclose(hp);
X	++fst;
X	return(0);
X}
Xrd_diykit(fp)
XFILE *fp;
X{
X	int i, lastc;
X	struct FNT_BITMAP *cf;
X	short cur_char;
X	char curchar[8];
X
X	for (cur_char=0;;)
X	{
X		lastc = cur_char;
X			/* not all machines are big endian ones */
X			/* diykit therefore stores cur_char as a */
X			/* 4 byte ascii string. It is, however written */
X			/* as a short. */
X		if ((i = fread(curchar, 4, 1, fp)) != 1)
X		{
X			if (cur_char > 0x7e && (!i))
X				break;
X			fprintf(stderr,"%s: read error %d in font\n",PGM,errno);
X			return(ERROR);
X		}
X		curchar[4] = '\0';
X		cur_char = (short)atoi(curchar);
X		if (cur_char <= 0x20 || cur_char > 0xff)
X		{
X			fprintf(stderr,"%s: illegal curchar value %04x after char %3d\n",
X				PGM,cur_char,lastc);
X			return(ERROR);
X		}
X		cf = &font[cur_char];
X
X		if ((cf->SH = (short *)malloc(bm_len * sizeof(short))) == (short *)NULL)
X		{
X			fprintf(stderr,"%s: not enough memory for bitmap array char %d\n",
X				PGM,cur_char);
X			return(ERROR);
X		}
X
X		if (fread(cf->SH, sizeof(short), bm_len, fp) != bm_len)
X		{
X			fprintf(stderr,"%s: read error %d for char bitmap %d\n",
X				PGM,errno,cur_char);
X			return(ERROR);
X		}
X		cf->active = TRUE;
X	}
X	return(0);
X}
Xwritekit(hp,kit)
XFILE *hp, *kit;
X{
X	struct FNT_BITMAP *cf;
X	short cur_char, i, pos;
X	char tmp[4];
X
X	if (bm_len == 16)
X		strcpy(tmp, "fxL");
X	else strcpy(tmp, "fxH");
X
X	if (fwrite(tmp, sizeof(char), 3, hp) != 3)
X	{
X		fprintf(stderr,"%s: write error %d on fontfile\n",PGM,errno);
X		return(ERROR);
X	}
X
X	for (cur_char=33; cur_char<128; cur_char++)
X	{
X		cf = &font[cur_char];
X		if (cf->active)
X		{
X			if (fwrite(&cur_char, sizeof(short), 1, hp) != 1)
X			{
X				fprintf(stderr,"%s: write error %d on font\n",
X					PGM,errno);
X				return(ERROR);
X			}
X			if (fwrite(cf->SH, sizeof(short), bm_len, hp) != bm_len)
X			{
X				fprintf(stderr,"%s: write error %d on font\n",
X					PGM,errno);
X				return(ERROR);
X			}
X		}
X	}
X
X	while ((cur_char = getnext_char(&pos,kit)) != EOF)
X	{
X		cf = &font[cur_char];
X		if (cf->active)
X		{
X			if (fwrite(&pos, sizeof(short), 1, hp) != 1)
X			{
X				fprintf(stderr,"%s: write error %d on font\n",
X					PGM,errno);
X				return(ERROR);
X			}
X			if (fwrite(cf->SH, sizeof(short), bm_len, hp) != bm_len)
X			{
X				fprintf(stderr,"%s: write error %d on font\n",
X					PGM,errno);
X				return(ERROR);
X			}
X		}
X	}
X	return(0);
X}
Xgetnext_char(pos,fp)
Xshort *pos;
XFILE *fp;
X{
X	char buf[128], charname[40];
X	int found, Pos;
X	static int line;
X
X	for (;;)
X	{
X		if (fgets(buf, 126, fp) == NULL)
X			return(EOF);
X		++line;
X		if (buf[0] != '#')
X		{
X			if (sscanf(buf,"%d %s",&Pos,charname) < 2)
X			{
X				fprintf(stderr,"%s: def file looks wrong to me at line %d\n",PGM,line);
X				return(EOF);
X			}
X			*pos = Pos;
X			if ((found = find_def(charname)) == EOF)
X			{
X				fprintf(stderr,"%s: unknown char def {%s} at at line %d\n",
X					PGM,charname,line);
X				return(EOF);
X			}
X			return(found);
X		}
X	}
X}
Xfind_def(s)
Xchar *s;
X{
X	int mid, cmp, hi,lo;
X
X	lo=0;
X	hi = MAX_DEF-1;
X	for (; lo<=hi;)
X	{
X		mid = (lo+hi)/2;
X		if ((cmp = strcmp(s, diy[mid].charname)) < 0)
X			hi = mid-1;
X		else if (cmp > 0)
X			lo = mid+1;
X		else return(diy[mid].chardef);
X	}
X	return(EOF);;
X}
Xmain()
X{
X	FILE *out, *kitfp;
X	char destname[256];
X
X	errno = 0;
X	if ((kitfp = fopen("diykit.def", "r")) == NULL)
X	{
X		fprintf(stderr,"%s: can't open diykit.def, errno %d\n",errno);
X		exit(1);
X	}
X
X	if (fgets(charset, 126, kitfp) == NULL)
X	{
X		fprintf(stderr,"%s: can't read charset info on 1st line, errno %d\n",
X			PGM,errno);
X		exit(1);
X	}
X	if (font_init("lores.data"))
X		exit(1);
X
X	sprintf(destname, "%s/%s", FAXLIB, FAXLFONT);
X	if ((out = fopen(destname, "w")) == NULL)
X	{
X		fprintf(stderr,"%s: can't create %s, errno %d\n",
X			PGM,destname,errno);
X		exit(1);
X	}
X	writekit(out,kitfp);
X	fclose(out);
X	chmod(destname, 0644);
X
X	errno = 0;
X	rewind(kitfp);
X	if (fgets(charset, 126, kitfp) == NULL)
X	{
X		fprintf(stderr,"%s: can't read charset info on 1st line, errno %d\n",
X			PGM,errno);
X		exit(1);
X	}
X	if (font_init("hires.data"))
X		exit(1);
X
X	sprintf(destname, "%s/%s", FAXLIB, FAXHFONT);
X	if ((out = fopen(destname, "w")) == NULL)
X	{
X		fprintf(stderr,"%s: can't create %s, errno %d\n",
X			PGM,destname,errno);
X		exit(1);
X	}
X	writekit(out,kitfp);
X	fclose(out);
X	fclose(kitfp);
X	chmod(destname, 0644);
X
X	exit(0);
X}
END_OF_FILE
  if test 5399 -ne `wc -c <'faxhost/faxfonts/diykit.c'`; then
    echo shar: \"'faxhost/faxfonts/diykit.c'\" unpacked with wrong size!
  fi
  # end of 'faxhost/faxfonts/diykit.c'
fi
if test -f 'faxhost/sendfax.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'faxhost/sendfax.c'\"
else
  echo shar: Extracting \"'faxhost/sendfax.c'\" \(20157 characters\)
  sed "s/^X//" >'faxhost/sendfax.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <malloc.h>
X#include <fcntl.h>
X#include <errno.h>
X#include <time.h>
X#include <sys/types.h>
X#include <dirent.h>
X#include <unistd.h>
X
X#include "../faxconfig.h"
X
X/*
X	sendfax.c
X
X	called frequently by cron,
X	inspect spool area for jobs to do - and get on with it
X	the actual squirting of data through the serial ports
X	is done in wiring.c
X	this file is concerned mainly with reading config info,
X	collecting and parsing all available x.files and
X	passing them on to forked copies of sendfax to share
X	the load
X
X	if you have only one faxmodem, all work is done in house
X	without forking off slave clones
X
X	first released version 0.99 [desperado version]
X	cleaned up Jan 22nd '91,
X	Copyright (C) 1991, klaus schallhorn, klaus@cnix.uucp
X
X	Permission to use, copy, modify, and distribute this software 
X	and its documentation for any purpose and without fee is hereby 
X	granted, provided that the above copyright notice appear in 
X	all copies and that both that copyright notice and this permission 
X	notice appear in supporting documentation. 
X
X	This software is provided "as is" without express or implied warranty.
X*/
X
X#define	COME_BACK	0
X#define	GO_AWAY		1
X
X#define	ALLOWED		1	/* individual permissions, same as cron/at */
X#define	DENIED		2	/* files: fax.allow, fax.deny */
X#define	ROOT		3
X#define	ALL		4
X
Xchar	faxrun[256],		/* make a note that's sendfax is running */
X	tmp[1024],
X	io[1024];
X
X
Xchar	**faxjobs;		/* list of x.files, jobs to do */
Xchar	**Denied, **Allowed;	/* fax permissions, same setup as cron */
Xchar	**CanNow;		/* in case the boss wants to override hours */
X
Xstatic	int pid,		/* zip 'em all out to zero */
X	max_age,		/* days a fax may hover in spool dir */
X	max_tries,		/* max no of attempts to tx a fax [job] */
X	faxperms,		/* checking fax.allow && fax.deny */
X	a_cnt, d_cnt,		/* number of allowed/denied users */
X	cn_cnt,			/* no of unrestricted users */
X	dev_cnt, 		/* number of devices faxable */
X	todo;			/* no of fax jobs in queue */
X
Xint	blah;			/* chattynes for logging */
X
Xstruct	Hours			/* restrict certain area/country codes to cheap hours, */
X{				/* or local faxes only between midday and noon */
X	char *dialcode;
X	char hours[24];
X} *hour_ptr;
Xstatic	int h_entries;
X
X
Xstruct config_funcs		/* to read fax.config in any order */
X{
X	int	(*funcptr)();		/* function address */
X	char	*funcname;		/* name used in config file */
X};
X
Xint	device(), incoming(), hours(), maxage(), maxtry(), loglevel();
Xchar	**Devices,		/* array of device names in /dev */
X	**Devlocks,		/* array of lock file names */
X	**Faxtypes,		/* array of fax modem types */
X	**Wakeup,		/* array of strings to revive modems */
X	*Dialtyp,		/* array of T's or P's [tone/pulse] */
X	*Topspeed;		/* array of one byte speed indicators */
X
Xstruct config_funcs config_table[] = 
X{
X/*	address		funcname	*/
X	{ device,	"device"	},
X	{ incoming,	"incoming"	},
X	{ hours,	"hours"		},
X	{ maxage,	"maxage"	},
X	{ maxtry,	"maxtry"	},
X	{ loglevel,	"loglevel"	}
X};
X#define	MAX_CONFIG	sizeof(config_table)/sizeof(struct config_funcs)
X
Xstruct	FAX fax;
X
Xextern	int errno;
XFILE	*popen();
X
X
Xmain(ac,av)
Xint ac;
Xchar *av[];
X{
X	char *PGM;
X
X	errno = blah = 0;
X	hour_ptr = NULL;
X	Topspeed = Dialtyp = NULL;
X	Allowed = Denied = CanNow = NULL;
X	Devices = Devlocks = Faxtypes = Wakeup = NULL;
X
X	pid = getpid();
X
X	if ((PGM = strrchr(av[0], '/')) != NULL)
X		PGM++;
X	else PGM = av[0];
X
X#ifndef	TESTING
X	if (fork())	/* errs, parent, or unwanted relatives */
X		exit(0);
X	if (setpgrp(0,0))
X	{
X		fax_log(ERROR, "sendfax: can't create new prgp\n");
X		exit(1);
X	}
X#endif
X
X	if (chdir(FAXSPOOL))	/* quick one, job done */
X	{
X		fax_log(ERROR,"sendfax: can't cd to FAXSPOOL\n");
X		exit(1);
X	}
X	if (read_config())
X		exit(1);
X
X	if (!strcmp(PGM, "rcvfax"))
X		exit(0);	/*rcvfax(); when done */
X	else			/* sendfax */
X	{			/* see if sendfax is active, if so, go away */
X		sprintf(faxrun, "%s/SEND.FAX.RUN",FAXLIB);
X		if (mklock(faxrun, FALSE, FALSE) < 0)
X		{
X			fax_log(5, "sendfax: busy\n");
X			exit(0); /* last cron job of sendfax still busy */
X		}
X		if ((todo = chk_queue()) > 0)
X		{
X			if (!blah)
X				fax_log(0, "sendfax: STARTUP, %d device%c, %d jobs pending\n",
X					dev_cnt,(dev_cnt>1)?'s':' ',todo);
X			else fax_log(9, "sendfax: %d jobs pending\n",todo);
X			runqueue();
X		}
X		fax_log(5, "sendfax: done\n");
X		unlink(faxrun);
X	}
X	exit(0);
X}
X
Xrunqueue()
X{
X	int i, j, k, brk, in_use, slot, *kid_pids;
X	FILE *X;
X
X	fax.phone = NULL;
X
X	if (dev_cnt > 1)	/* do this only if more than 1 faxmodem */
X	{
X		if ((kid_pids = (int *)malloc(dev_cnt * sizeof(int))) == NULL)
X		{
X			fax_log(ERROR,"sendfax: can't allocate memory\n");
X			return;
X		}
X		for (i=0; i<dev_cnt; i++)
X			kid_pids[i] = 0;
X	}
X
X	fax.phone_nos = 0;
X	for (i=in_use=slot=0; i<todo; i++)
X	{
X		fax.tries = fax.uid = fax.now = 
X			fax.mail = fax.pages = 0;
X		fax.user[0] = fax.dname[0] = '\0';
X#ifdef	JOBID
X		fax.jobid[0] = '\0';
X#endif
X		fax.tpos = fax.ppos = fax.spooled = 0L;
X
X		if ((X = fopen(faxjobs[i], "r+")) == NULL)
X		{
X			fax_log(ERROR,"sendfax: can't open %s\n",faxjobs[i]);
X			return;
X		}
X
X		if (read_job(X, faxjobs[i]))
X		{
X			fax_log(ERROR,"sendfax: can't read %s\n",faxjobs[i]);
X			return;
X		}
X		fax_log(5, "sendfax: %s, %d fax%s, attempt %d, user %s%s\n",
X			faxjobs[i], fax.phone_nos, (fax.phone_nos>1)?"es":"",
X			fax.tries, fax.user,
X			(fax.tries < max_tries)?"":", CANNOT RETRY");
X
X		if (fax.tries >= max_tries)
X		{
X			fclose(X);
X			continue;
X		}
X
X		if (chk_perms())
X		{
X			fclose(X);
X			fax_log(ERROR,"sendfax: user %s not permitted to use fax, mailed user, unlinked files\n",fax.user);
X			rmjob(faxjobs[i],fax.dname,fax.pages);
X			sprintf(tmp,"echo 'you have no permission to fax [fax admin: %s]' | mail %s",FAXADMIN,fax.user);
X			system(tmp);
X			continue;
X		}
X
X/*
X	can no longer avoid the issue.
X	if we have just 1 faxmodem, squirt one job now,
X	if we're sharing the load between several devices, find
X	an unused one and fork a copy to do the sending. If no
X	faxmodems avail, wait for one to pop up.
X
X	All this assumes uucp is not interfering, this is checked
X	in "wiring.c", where we just die away [or return in case
X	of just 1 device] if port cannot be opened
X*/
X		if (dev_cnt == 1)
X		{
X			sendfax(X, slot, COME_BACK);
X			continue;
X		}
X
X		for (k=0; k<dev_cnt; k++)
X			if (!kid_pids[k])
X			{
X				slot = k;
X				break;
X			}
X
X		if ((j = fork()) == ERROR)
X		{
X			fax_log(ERROR,"sendfax: can't fork, giving up\n");
X			return;
X		}
X		else if (!j)	/* child */
X			sendfax(X, slot, GO_AWAY);
X
X		fclose(X);	/* still open in child for read/write */
X		kid_pids[slot] = j;	/* associate kid's pid with dev */
X
X		if (++in_use < dev_cnt)
X			continue;
X
X		for (brk=0; !brk;)
X		{
X			j = wait((int *)NULL);	/* don't wanna know x status */
X			for (k=0; k<dev_cnt; k++)
X				if (j == kid_pids[k])
X				{		/* make device recycleable */
X					kid_pids[k] = 0;
X					--in_use;
X					brk = TRUE; /* have an unused device */
X					break;	    /* brk top loop to go on */
X				}
X		}
X	}
X}
X
Xchk_queue()
X{
X	DIR *dirp;
X	struct dirent *dp;
X	int alloced, entries, i;
X
X	if ((dirp = opendir(FAXSPOOL)) == NULL)
X		return(fax_log(ERROR,"sendfax: can't open directory %s\n",FAXSPOOL));
X
X	if ((faxjobs = (char **)malloc(8*sizeof(char *))) == NULL)
X		return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X	alloced = 8;
X	entries = 0;
X
X	for (;;)
X	{
X		if (entries == alloced)
X		{
X			if ((faxjobs = (char **)realloc(faxjobs,
X				(alloced += 8) * sizeof(char *))) == NULL)
X				return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X		}
X
X		if ((dp = readdir(dirp)) == NULL)
X			break;
X		if (strncmp(dp->d_name, "x.f", 3))
X			continue;
X
X		if ((faxjobs[entries] = malloc(1+strlen(dp->d_name))) == NULL)
X			return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X		strcpy(faxjobs[entries++], dp->d_name);
X	}
X	closedir(dirp);
X	i = entries;
X	while (i < alloced)
X		faxjobs[i++] = NULL;
X	return(entries);
X}
Xread_config()
X{
X	FILE *cfg;
X	char a[256];
X	int i;
X
X	sprintf(a, "%s/fax.config", FAXLIB);
X	if ((cfg = fopen(a, "r")) == NULL)
X	{
X		fax_log(ERROR,"sendfax: can't open %s/fax.config\n",FAXLIB);
X		return(ERROR);
X	}
X
X	while (fgets(io, 254, cfg) != NULL)
X	{
X		if (io[0] == '#' || (sscanf(io, "%s",a) < 1))
X			continue;
X		for (i=0; i<MAX_CONFIG; i++)
X			if (!strcmp(a,config_table[i].funcname))
X			{
X				if ((*config_table[i].funcptr)
X					(&io[fstbyte(io,strlen(a))]))
X				{
X					fax_log(ERROR,
X						"strange device spec [%s]\n",io);
X					return(ERROR);
X				}
X				break;
X			}
X		if (i == MAX_CONFIG)
X			fax_log(ERROR,"sendfax: unknown function in config: %s\n",a);
X	}
X	fclose(cfg);
X	if (blah >= 5)	/* alternative STARTUP log is in main with blah == 0 */
X		fax_log(5, "sendfax: STARTUP, %d device%c\n",dev_cnt,(dev_cnt>1)?'s':' ');
X	if (get_perms())
X		return(ERROR);
X	return(0);
X}
Xfstbyte(s,skip)	/* find fst usable item in a config line like: */
Xchar *s;	/* device /dev/copperwire */
Xint skip;
X{
X	s += skip;
X	while (*s && isspace(*s))
X	{
X		++skip;
X		++s;
X	}
X	return(skip);
X}
Xnxtint(s)
Xchar *s;
X{
X	char *o;
X
X	o = s;
X	while (*s && (isdigit(*s) || *s == '-'))
X		++s;
X	while (*s && isspace(*s))
X		++s;
X	return((int)(s - o));
X}
Xdevice(s)
Xchar *s;
X{
X	static int d_alloced;
X	char dev[80], devlck[80], faxtyp[80], dial, speed, *sptr, *eptr;
X
X	if (sscanf(s,"%s %s %s %c %c",dev,devlck,faxtyp,&dial,&speed) < 5)
X		return(ERROR);
X
X	if (!d_alloced)
X	{
X		if (((Devices = (char **)malloc(4*sizeof(char *))) == NULL)
X		    || ((Devlocks = (char **)malloc(4*sizeof(char *))) == NULL)
X		    || ((Faxtypes = (char **)malloc(4*sizeof(char *))) == NULL)
X		    || ((Wakeup = (char **)malloc(4*sizeof(char *))) == NULL)
X		    || ((Dialtyp = (char *)malloc(4)) == NULL)
X		    || ((Topspeed = (char *)malloc(4)) == NULL))
X			return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X		d_alloced = 4;
X	}
X	else if (d_alloced == dev_cnt)
X	{
X		d_alloced += 4;
X		if (((Devices = (char **)realloc(Devices,
X			d_alloced * sizeof(char *))) == NULL)
X		    || ((Devlocks = (char **)realloc(Devlocks,
X			d_alloced * sizeof(char *))) == NULL)
X		    || ((Faxtypes = (char **)realloc(Faxtypes,
X			d_alloced * sizeof(char *))) == NULL)
X		    || ((Wakeup = (char **)realloc(Wakeup,
X			d_alloced * sizeof(char *))) == NULL)
X		    || ((Dialtyp = (char *)realloc(Dialtyp,
X			d_alloced)) == NULL)
X		    || ((Topspeed = (char *)realloc(Topspeed,
X			d_alloced)) == NULL))
X			return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X	}
X	if (((Devices[dev_cnt] = malloc(1+strlen(dev))) == NULL)
X	    || ((Devlocks[dev_cnt] = malloc(1+strlen(devlck))) == NULL)
X	    || ((Faxtypes[dev_cnt] = malloc(1+strlen(faxtyp))) == NULL))
X		return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X	strcpy(Devices[dev_cnt],  dev);
X	strcpy(Devlocks[dev_cnt], devlck);
X	strcpy(Faxtypes[dev_cnt], faxtyp);
X	Dialtyp[dev_cnt] = dial;
X	Topspeed[dev_cnt] = speed;
X
X	if (((sptr = strchr(s, '"')) != NULL)
X		&& ((eptr = strrchr(s, '"')) != NULL)
X		&& (eptr > sptr))
X	{
X		*eptr = '\0';
X		++sptr;
X		if ((Wakeup[dev_cnt] = malloc(1+(int)(eptr-sptr))) == NULL)
X			return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X		strcpy(Wakeup[dev_cnt], sptr);
X	}
X	else Wakeup[dev_cnt] = NULL;
X
X	++dev_cnt;
X	return(0);
X}
Xincoming(s)
Xchar *s;
X{
X/*	haven't had time to do this
X	if (sscanf(s,"%s",Incoming) < 1)
X*/
X		return(ERROR);
X}
Xmaxtry(s)
Xchar *s;
X{
X	if (sscanf(s,"%d",&max_tries) < 1)
X		return(ERROR);
X	return(0);
X}
Xloglevel(s)
Xchar *s;
X{
X	if (sscanf(s,"%d",&blah) < 1)
X		return(ERROR);
X	return(0);
X}
Xmaxage(s)
Xchar *s;
X{
X	if (sscanf(s,"%d",&max_age) < 1)
X		return(ERROR);
X	return(0);
X}
Xhours(s)
Xchar *s;
X{
X	static int h_alloced;
X	int i, lasth;
X	char *p;
X
X	if (sscanf(s,"%s",tmp) < 1)	/* expect dial code */
X		return(ERROR);
X	i = strlen(tmp);
X	s += fstbyte(s, i);			/* skip him */
X
X	if (!h_entries)
X	{
X		if ((hour_ptr = (struct Hours *)malloc(
X				(h_alloced += 8) * sizeof(struct Hours))) == NULL)
X			return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X	}
X	else if (h_alloced == h_entries)
X	{
X		if ((hour_ptr = (struct Hours *)realloc(hour_ptr,
X				(h_alloced += 8) * sizeof(struct Hours))) == NULL)
X			return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X	}
X	if ((hour_ptr[h_entries].dialcode = malloc(1+i)) == NULL)
X		return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X	strcpy(hour_ptr[h_entries].dialcode, tmp);
X
X	p = hour_ptr[h_entries].hours;
X	for (i=0; i<24; i++)
X		*p++ = '\0';
X
X	lasth = -1;
X	p = hour_ptr[h_entries].hours;
X
X	while (*s && *s != '#')
X	{
X		if (isdigit(*s))
X		{
X			if ((i = atoi(s)) < 0 || i > 23)
X				return(ERROR);
X			p[i] = '\1';
X			if (lasth > -1)
X			{
X				if (lasth < i)
X				{
X					while (lasth < i)
X						p[lasth++] = '\1';
X				}
X				else
X				{
X					while (lasth < 24)
X						p[lasth++] = '\1';
X					lasth = 0;
X					while (lasth < i)
X						p[lasth++] = '\1';
X				}
X				lasth = -1;
X			}
X			s += nxtint(s);
X		}
X		else if (*s == '-')
X		{
X			lasth = i;
X			s += nxtint(s);
X		}
X	}
X	++h_entries;
X	return(0);
X}
X#define	MATCHCMASK	0377
X#define	MATCHQUOTE	0200
X#define	MATCHQMASK	(MATCHCMASK&~MATCHQUOTE)
X#define	MATCHNOT	'^'
X
Xstatic	char	*cclass();
X
Xmatch(s, p)
Xchar *s, *p;
X{
X	int sc, pc;
X
X	while ((pc = *p++ & MATCHCMASK) != '\0')
X	{
X		sc = *s++ & MATCHQMASK;
X		switch (pc)
X		{
X		case '[':
X			if ((p = cclass(p, sc)) == NULL)
X				return(0);
X			break;
X		case '?':
X			if (sc == 0)
X				return(0);
X			break;
X		case '*':
X			s--;
X			do
X			{
X				if (*p == '\0' || match(s, p))
X					return(1);
X			} while (*s++ != '\0');
X			return(0);
X		default:
X			if (sc != (pc & ~MATCHQUOTE))
X				return(0);
X		}
X	}
X	return(*s == 0);
X}
X
Xstatic char *cclass(p, sub)
Xchar *p;
Xint sub;
X{
X	int c, d, not, found;
X
X	if ((not = *p == MATCHNOT) != 0)
X		p++;
X	found = not;
X
X	do
X	{
X		if (*p == '\0')
X			return(NULL);
X		c = *p & MATCHCMASK;
X		if (p[1] == '-' && p[2] != ']')
X		{
X			d = p[2] & MATCHCMASK;
X			p++;
X		}
X		else d = c;
X
X		if (c == sub || c <= sub && sub <= d)
X			found = !not;
X	} while (*++p != ']');
X
X	return(found ? (p+1) : NULL);
X}
Xget_perms()
X{
X	FILE *fp;
X	int a_alloced, d_alloced, len;
X
X	a_alloced = d_alloced = 0;
X	sprintf(tmp, "%s/fax.allow", FAXLIB);
X	if ((fp = fopen(tmp, "r")) != NULL)
X	{
X		if ((Allowed = (char **)malloc(8*sizeof(char *))) == NULL)
X			return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X		a_alloced = 8;
X
X		for (;;)
X		{
X			if (a_cnt == a_alloced)
X			{
X				if ((Allowed = (char **)realloc(Allowed,
X					(a_alloced += 8) * sizeof(char *))) == NULL)
X					return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X			}
X
X			if (fgets(tmp, 128, fp) == NULL)
X				break;
X			if ((len = strlen(tmp)) == 0)
X				break;
X
X			tmp[--len] = '\0';
X			if (!len)
X				continue;
X			if ((Allowed[a_cnt] = malloc(1+len)) == NULL)
X				return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X			strcpy(Allowed[a_cnt++], tmp);
X		}
X		if (a_cnt)
X			faxperms = ALLOWED;
X		fclose(fp);
X	}
X	else
X	{
X		sprintf(tmp, "%s/fax.deny", FAXLIB);
X		if ((fp = fopen(tmp, "r")) != NULL)
X		{
X			if ((Denied = (char **)malloc(8*sizeof(char *))) == NULL)
X				return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X			d_alloced = 8;
X
X			for (;;)
X			{
X				if (d_cnt == d_alloced)
X				{
X					if ((Denied = (char **)realloc(Denied,
X						(d_alloced += 8) * sizeof(char *))) == NULL)
X						return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X				}
X
X				if (fgets(tmp, 128, fp) == NULL)
X					break;
X				if ((len = strlen(tmp)) == 0)
X					break;
X
X				tmp[--len] = '\0';
X				if (!len)
X					continue;
X				if ((Denied[d_cnt] = malloc(1+len)) == NULL)
X					return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X				strcpy(Denied[d_cnt++], tmp);
X			}
X			if (d_cnt)
X				faxperms = DENIED;
X			else faxperms = ALL;
X			fclose(fp);
X		}
X	}
X	if (!faxperms)
X		faxperms = ROOT;
X	return(get_boss_perms());
X}
Xget_boss_perms()
X{
X	FILE *fp;
X	int cn_alloced, len;
X
X	cn_alloced = 0;
X	sprintf(tmp, "%s/fax.always", FAXLIB);
X	if ((fp = fopen(tmp, "r")) != NULL)
X	{
X		if ((CanNow = (char **)malloc(8*sizeof(char *))) == NULL)
X			return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X		cn_alloced = 8;
X
X		for (;;)
X		{
X			if (cn_cnt == cn_alloced)
X			{
X				if ((CanNow = (char **)realloc(CanNow,
X					(cn_alloced += 8) * sizeof(char *))) == NULL)
X					return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X			}
X
X			if (fgets(tmp, 128, fp) == NULL)
X				break;
X			if ((len = strlen(tmp)) == 0)
X				break;
X			tmp[--len] = '\0';
X			if (!len)
X				continue;
X			if ((CanNow[cn_cnt] = malloc(1+len)) == NULL)
X				return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X			strcpy(CanNow[cn_cnt++], tmp);
X		}
X		fclose(fp);
X	}
X	fax_log(3, "sendfax: faxperms %d, allowed %d, denied %d, always %d\n",
X		faxperms, a_cnt, d_cnt, cn_cnt);
X	return(0);
X}
Xread_job(fp, xn)
XFILE *fp;
Xchar *xn;
X{
X	int i;
X
X	if (fax.phone_nos)	/* has been called before, clean up */
X	{
X		for (i=0; i<fax.phone_nos; i++)
X			if (fax.phone[i] != NULL)
X				free(fax.phone[i]);
X		free(fax.phone);
X		fax.phone = NULL;
X		fax.phone_nos = 0;
X	}
X
X/*
X	these are read in the order they're written
X	by the spooler, not they way the structure is designed
X*/
X	if (getint(fp,&fax.spooled))	/* spool timestamp */
X		return(ERROR);
X	fax.tpos = ftell(fp);	/* might need to rewrite no of attempts */
X	if (getint(fp,&fax.tries)
X		|| getstring(fp,fax.user) || getint(fp,&fax.uid)
X		|| getint(fp,&fax.now) || getint(fp,&fax.mail)
X		|| getint(fp,&fax.type)
X		|| getint(fp,&fax.hires)
X		|| getstring(fp,tmp)	/* font, don't need to know this */
X		|| getstring(fp,tmp))	/* retfax, don't need to know either */
X		return(ERROR);
X	fax.ppos = ftell(fp);		/* if we succeed on partial phone list */
X	if ((fax.phone_nos = getphone(fp)) <= 0) /* rewrite those not yet done */
X		return(ERROR);
X	if (getstring(fp,fax.dname))
X		return(ERROR);
X	strcpy(fax.xname, xn);
X	if (getint(fp,&fax.pages))
X		return(ERROR);
X#ifdef	JOBID
X	if (getstring(fp,fax.jobid))
X		return(ERROR);
X#endif
X	return(0);
X}
Xgetstring(fp,s)
XFILE *fp;
Xchar *s;
X{
X	char buf[80];
X
X	if (fgets(io, 80, fp) == NULL)
X		return(ERROR);
X	if (sscanf(io, "%s %s",buf,s) != 2)
X		return(ERROR);
X	return(0);
X}
Xgetint(fp,n)
XFILE *fp;
Xint *n;
X{
X	long l;
X
X	if (fgets(io, 80, fp) == NULL)
X		return(ERROR);
X	if (sscanf(io, "%s %ld",tmp,&l) != 2)
X		return(ERROR);
X	*n = l;
X	return(0);
X}
Xgetphone(fp)
XFILE *fp;
X{
X	int i, p_entries=0, p_alloced=0;
X	char phone[80];
X	long oldpos;
X
X	if ((fax.phone = (char **)malloc(8*sizeof(char *))) == NULL)
X		return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X	p_alloced = 8;
X	p_entries = 0;
X
X	for (;;)
X	{
X		oldpos = ftell(fp);
X
X		if (p_entries == p_alloced)
X		{
X			if ((fax.phone = (char **)realloc(fax.phone,
X				(p_alloced += 8) * sizeof(char *))) == NULL)
X				return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X		}
X
X		if (fgets(io, 80, fp) == NULL)
X			return(ERROR);
X		if (io[0] == '#')
X			continue;
X		if (!strncmp(io, "data", 4))
X		{
X			fseek(fp, oldpos, 0);
X			break;
X		}
X		if (sscanf(io, "%s %s",tmp,phone) < 2)
X			return(ERROR);
X
X		if ((fax.phone[p_entries] = malloc(1+strlen(phone))) == NULL)
X			return(fax_log(ERROR,"sendfax: can't allocate memory\n"));
X		strcpy(fax.phone[p_entries++], phone);
X	}
X	for (i=p_entries; i<p_alloced; i++)
X		fax.phone[i] = NULL;
X	return(p_entries);
X}
Xchk_perms()
X{
X	int i;
X
X	if (faxperms == ALL)
X		return(FALSE);
X	else if ((faxperms == ROOT) && (!fax.uid))
X		return(FALSE);
X	else if (faxperms == ALLOWED)
X	{
X		for (i=0; i<a_cnt; i++)
X			if (!strcmp(fax.user, Allowed[i]))
X				return(FALSE);
X	}
X	else if (faxperms == DENIED)
X	{
X		for (i=0; i<d_cnt; i++)
X			if (!strcmp(fax.user, Denied[i]))
X				return(ERROR);
X		return(FALSE);
X	}
X	return(ERROR);
X}
Xnot_now(uid,now,phone)
Xint uid, now;
Xchar *phone;
X{
X	int i;
X	time_t cur;
X	struct tm *tml, *localtime();
X
X	if (fax.now)
X	{
X		if (!fax.uid) /* if root can edit fax.config it can fax now */
X			return(FALSE);
X		for (i=0; i<cn_cnt; i++)
X			if (!strcmp(fax.user, CanNow[i]))
X				return(FALSE);
X	}
X	
X	for (i=0; i<h_entries; i++)	/* check area/cty codes for restrictions */
X		if (match(phone, hour_ptr[i].dialcode))
X		{
X			(void)time(&cur);
X			tml = localtime(&cur);	/* if not allowed at this hour */
X			if (!hour_ptr[i].hours[tml->tm_hour])
X				return(ERROR);
X			return(FALSE);
X		}
X	return(FALSE);		/* no restrictions on this phone number */
X}
Xrmjob(xname,dname,pages)
Xchar *xname,*dname;
Xint pages;
X{
X	char buf[256], *d;
X	int i;
X
X	unlink(xname);
X	for (i=0; i<pages; i++)
X	{
X		sprintf(buf,"%s.g3.%d",dname,i);
X		unlink(buf);
X	}
X}
END_OF_FILE
  if test 20157 -ne `wc -c <'faxhost/sendfax.c'`; then
    echo shar: \"'faxhost/sendfax.c'\" unpacked with wrong size!
  fi
  # end of 'faxhost/sendfax.c'
fi
echo shar: End of archive 2 \(of 5\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 5 archives.
    rm -f ark[1-9]isdone
else
    echo You still must unpack the following archives:
    echo "        " ${MISSING}
fi
exit 0
exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.