[comp.sources.unix] v24i041: Email fax-sending package, Part03/05

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

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

#! /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:  faxclient/fax.c faxhost/spool.fax.c sample.fax.aliases
#   writefax.man
# Wrapped by rsalz@litchi.bbn.com on Wed Mar 13 14:08:02 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 3 (of 5)."'
if test -f 'faxclient/fax.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'faxclient/fax.c'\"
else
  echo shar: Extracting \"'faxclient/fax.c'\" \(14931 characters\)
  sed "s/^X//" >'faxclient/fax.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <malloc.h>
X#include <unistd.h>
X#include <pwd.h>
X#include <string.h>
X#include <signal.h>
X#include <sys/time.h>
X#include <sys/stat.h>
X
X#include "../faxconfig.h"
X
X#ifdef	NETWIDE_FAX
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <netdb.h>
X#endif
X
X
X/*
X	fax.c
X
X	accept fax from user.
X
X	src is either a file or stdin, dest is spooler somewhere on the net.
X	do some parsing && error checking before we invoke the spooler.
X	allow aliases and lists for destination fax.
X	argv[1] must be either a phone no [no alpha, just digits && ispunct()],
X	an alias [as found in $HOME/fax.aliases], or name of a fax list file.
X
X	format of alias file:
X	=====================
X	alias   phone no   ftao, starts with a colon	     optional comment
X	---------------------------------------------------------------------
X	fred    12345678   :for the attention of fred bloggs # comment
X	bill	98765
X	joe	7654323	   :The Lady in Pnik
X
X	format of fax list
X	==================
X	phone no   ftao, starts with a colon		opt. comment	
X	------------------------------------------------------------
X	12345678   :for the attention of fred bloggs    # comment
X	9274356						# no ftao
X	87340875   :z. Hd. Herrn Meier			# needs it on time
X
X	first released version 0.99 [desperado version]
X	cleaned up Jan 21st '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
Xextern	int errno;
X
Xchar	me[80], tmpname[256], io[256], *hpfont, **phone, **ftao, *fname,
X	*retfax, *home;
Xchar	*get_aka(), *get_list(), *getenv();
X
Xstruct	passwd *pwentry, *getpwuid();
Xint	now, mail, hires, entries, alloced, save, broken;
XFILE	*collect_msg();
Xvoid	breakread();
X
X
Xnoalpha(s)	/* allow digits and ispunct() in phone nos */
Xchar *s;
X{
X	while (*s)
X	{
X		if (isalpha(*s))
X			return(FALSE);
X		++s;
X	}
X	return(TRUE);
X}
Xfstbyte(s,skip)
Xchar *s;
Xint skip;
X{
X	s += skip;
X	while (*s && isspace(*s))
X	{
X		++skip;
X		++s;
X	}
X	return(skip);
X}
Xvoid get_rc()	/* read user defaults stashed in $HOME/.faxrc */
X{
X	FILE *rc;
X	char *ptr, *save_str();
X
X	if (*home == '/' && *(home+1) == '\0')
X		strcpy(io,"/.faxrc");
X	else sprintf(io,"%s/.faxrc",home);
X
X	if ((rc = fopen(io, "r")) == NULL)
X		return;
X
X	while (fgets(io, 248, rc) != NULL)
X	{
X		if (io[0] == '#')
X			continue;
X
X		if ((ptr = strchr(io, '\n')) != NULL)
X			*ptr = '\0';
X		ptr = io;
X		if (!strncmp(io, "font", 4))
X		{
X			ptr += fstbyte(io, 4);
X			hpfont = save_str(ptr);
X		}
X		else if (!strncmp(io, "resolution", 10))
X		{
X			ptr += fstbyte(io, 10);
X			hires = get_bool(ptr, "high");
X		}
X		else if (!strncmp(io, "mail", 4))	/* mail success msg */
X		{
X			ptr += fstbyte(io, 4);
X			mail = get_bool(ptr, "true");
X		}
X		else if (!strncmp(io, "now", 3))	/* send now */
X		{
X			ptr += fstbyte(io, 3);
X			now = get_bool(ptr, "true");
X		}
X		else if (!strncmp(io, "save", 4))	/* save in $HOME/FaxSent */
X		{
X			ptr += fstbyte(io, 4);
X			save = get_bool(ptr, "true");
X		}
X		else if (!strncmp(io, "retfax", 6))	/* return faxno */
X		{
X			ptr += fstbyte(io, 6);
X			retfax = save_str(ptr);
X		}
X	}
X}
Xchar *save_str(s)
Xchar *s;
X{
X	char *p;
X
X	if ((p = malloc(1+strlen(s))) == NULL)
X	{
X		fprintf(stderr,"can't allocate memory\n");
X		exit(1);
X	}
X	strcpy(p, s);
X	return(p);
X}
Xget_bool(from,true)
Xchar *from, *true;
X{
X	if (!strncmp(from, true, strlen(true)))
X		return(TRUE);
X	return(FALSE);
X}
X
Xchar *get_aka(s) /* allocate and return a phone number for an alias */
Xchar *s;
X{
X	char tmp[256], phoneno[80], alias[80], *ptr, *eptr;
X	FILE *fp;
X	int len, found;
X
X	errno = 0;
X	if (*home == '/' && *(home+1) == '\0')
X		strcpy(tmp,"/fax.aliases");
X	else sprintf(tmp,"%s/fax.aliases",home);
X
X	len = strlen(s);
X	found = 0;
X	if ((fp = fopen(tmp, "r")) != NULL)
X	{
X		while (fgets(tmp, 248, fp) != NULL)
X		{
X			if (sscanf(tmp, "%s %s",alias,phoneno) < 2)
X				continue;
X			if (!strcmp(s, alias, len))
X			{
X				found = TRUE;
X				break;
X			}
X		}
X		fclose(fp);
X	}
X	if (!found)	/* check if there's a file by that name */
X	{
X		if ((phone[0] = get_list(s)) == NULL)
X		{
X			fprintf(stderr,"no alias for %s, no faxlist %s\n",s,s);
X			return(NULL);
X		}
X		return(phone[0]);
X	}
X
X	if ((phone[0] = malloc(1+strlen(phoneno))) == NULL)
X	{
X		fprintf(stderr,"can't allocate memory\n");
X		return(NULL);
X	}
X	strcpy(phone[0], phoneno);
X	if ((ptr = strchr(tmp, ':')) != NULL)
X	{
X		if ((eptr = strrchr(tmp, '#')) != NULL)
X			*eptr = '\0';
X		if ((ftao[0] = malloc(1+strlen(++ptr))) == NULL)
X		{
X			fprintf(stderr,"can't allocate memory\n");
X			return(NULL);
X		}
X		strcpy(ftao[0], ptr);
X	}
X	++entries;
X	return(phone[0]);
X}
Xchar *get_list(name)	/* read and allocate a list of phone nos */
Xchar *name;
X{
X	static char tmp[256], phoneno[80], *fname0, *fname1, *ptr, *eptr;
X	FILE *fp;
X	int i;
X
X		/* check listnames: 
X			if name[0] == '/', use absolute path
X			else check ".", then $HOME
X		*/
X	errno = 0;
X	if (*name == '/')
X	{
X		fname0 = name;
X		fname1 = NULL;
X	}
X	else
X	{
X		if (*home == '/' && *(home+1) == '\0')
X			sprintf(tmp,"/%s",name);
X		else sprintf(tmp,"%s/%s",home,name);
X		fname0 = name;
X		fname1 = tmp;
X	}
X
X	if ((fp = fopen(fname0, "r")) == NULL)
X		if ((fp = fopen(fname1, "r")) == NULL)
X			return(NULL);
X
X	while (fgets(tmp, 248, fp) != NULL)
X	{
X		if (sscanf(tmp, "%s",phoneno) < 1 || tmp[0] == '#')
X			continue;
X
X		if ((phone[entries] = malloc(1+strlen(phoneno))) == NULL)
X		{
X			fprintf(stderr,"can't allocate memory\n");
X			return(NULL);
X		}
X		strcpy(phone[entries], phoneno);
X
X		if ((ptr = strchr(tmp, ':')) != NULL)
X		{
X			if ((eptr = strrchr(tmp, '#')) != NULL)
X				*eptr = '\0';
X			if ((ftao[entries] = malloc(1+strlen(++ptr))) == NULL)
X			{
X				fprintf(stderr,"can't allocate memory\n");
X				return(NULL);
X			}
X			strcpy(ftao[entries], ptr);
X		}
X		else ftao[entries] = NULL;
X
X		if (++entries == alloced) /* reshuffle base ptrs */
X		{
X			if ((phone = (char **)realloc(phone,
X				((alloced + 8) * sizeof(char *)))) == NULL)
X			{
X				fprintf(stderr,"can't allocate memory\n");
X				return(NULL);
X			}
X				/* increment alloced now */
X			if ((ftao = (char **)realloc(ftao,
X				((alloced += 8) * sizeof(char *)))) == NULL)
X			{
X				fprintf(stderr,"can't allocate memory\n");
X				return(NULL);
X			}
X		}
X	}
X	fclose(fp);
X	for (i=entries; i<alloced; i++)
X		phone[i] = ftao[i] = NULL;
X	return(phone[0]);
X}
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X#ifdef	NETWIDE_FAX
X	struct hostent *hent;
X	struct sockaddr_in sin;
X	struct servent *sent;
X	int s;
X#endif
X	int i, ac, piped, type;
X	FILE *ofp, *faxfp;
X
X	if (argc == 1)
X	{
X		fprintf(stderr,"fax phone [file], -opt for options\n");
X		exit(1);
X	}
X
X	if ((home = getenv("HOME")) == NULL)
X	{
X		fprintf(stderr,"you're homeless\n");
X		exit(1);
X	}
X	if (argc == 2 && (!strncmp(argv[1], "-opt", 4)))	/* usage */
X		usage();
X
X	if ((pwentry = getpwuid(getuid())) == NULL)
X	{
X		fprintf(stderr,"you don't exist {%d}\n",errno);
X		exit(1);
X	}
X	setuid(getuid());
X	setgid(getgid());
X
X	piped = 0;
X	now = mail = hires = save = 0;
X	type = ASCII;
X	hpfont = retfax = fname = (char *)NULL;
X	ofp = faxfp = (FILE *)NULL;
X	me[0] = tmpname[0] = '\0';
X
X	if ((phone = (char **)malloc(8*sizeof(char *))) == NULL)
X		fprintf(stderr,"can't allocate memory");
X	if ((ftao = (char **)malloc(8*sizeof(char *))) == NULL)
X		fprintf(stderr,"can't allocate memory");
X	for (i=0; i<8; i++)
X		phone[i] = ftao[i] = NULL;
X	alloced = 8;
X	entries = 0;
X
X	get_rc();
X
X	for (ac=1; ac<argc; ac++)
X	{
X		if (phone[0] == NULL) /* first av[] is phone no, alias or list */
X		{
X			if (noalpha(argv[ac]))
X			{
X				phone[0] = argv[ac];
X				entries = 1;
X			}
X			else if ((phone[0] = get_aka(argv[ac])) == NULL)
X				exit(1);
X		}
X		else if (!strncmp(argv[ac], "-a", 2))	/* attn: fred bloggs */
X		{
X			ftao[0] = &argv[ac][2];
X			entries = 1;
X		}
X		else if (!strncmp(argv[ac], "-f", 2))	/* use hp compat font */
X			hpfont = &argv[ac][2];
X		else if (!strncmp(argv[ac], "-h", 2))	/* high res, expensive */
X			hires = TRUE;
X		else if (!strncmp(argv[ac], "-l", 2))	/* low res */
X			hires = FALSE;
X		else if (!strncmp(argv[ac], "-m", 2))	/* mail success msg */
X			mail = TRUE;
X		else if (!strncmp(argv[ac], "-n", 2))	/* send now */
X			now = TRUE;
X		else if (!strncmp(argv[ac], "-r", 2))	/* return faxno */
X			retfax = &argv[ac][2];
X		else if (!strncmp(argv[ac], "-s", 2))	/* save in $HOME/FaxSent */
X			save = TRUE;
X		else fname = argv[ac];
X	}
X
X	if (phone[0] == NULL)
X	{
X		fprintf(stderr,"no recipient\n");
X		exit(1);
X	}
X	if (fname == NULL)
X	{
X		if (isatty(fileno(stdin)))
X			fprintf(stderr,"reading stdin:\n");
X		if ((faxfp = collect_msg()) == NULL)
X			exit(1);
X	}
X	else if ((faxfp = fopen(fname, "r")) == NULL)
X	{
X		fprintf(stderr,"can't open %s for input\n",fname);
X		exit(1);
X	}
X
X#ifdef	NETWIDE_FAX
X				/* that's me, with a little bit of luck */
X	if (gethostname(me, 80))
X	{
X		fprintf(stderr,"I don't exist {%d}\n",errno);
X		exit(1);
X	}
X
X	if ((hent = gethostbyname(FAXHOST)) == NULL)
X	{
X		fprintf(stderr,"%s not known {%d}\n",FAXHOST,errno);
X		exit(1);
X	}
X
X	if (strcmp(me, hent->h_name))		/* FAXHOST != me */
X	{
X		if ((sent = getservbyname(FAXSERVER, "tcp")) == NULL)
X		{
X			fprintf(stderr,"%s service not known {%d}\n",FAXSERVER,errno);
X			exit(1);
X		}
X
X		/* grab a socket */
X		if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
X		{
X			fprintf(stderr," can't grab a socket {%d}\n",errno);
X			exit(1);
X		}
X		sin.sin_family = AF_INET;
X		sin.sin_port = htons(sent->s_port);
X		bcopy(hent->h_addr, &sin.sin_addr, hent->h_length);
X
X		/* now try to connect */
X		if (connect(s, &sin, sizeof(sin)) < 0)
X		{
X			fprintf(stderr,"can't connect {%d}\n",errno);
X			exit(1);
X		}
X		if ((ofp = fdopen(s, "w")) == NULL)
X		{
X			fprintf(stderr,"can't open socket for buffered write {%d}\n",errno);
X			exit(1);
X		}
X	}
X	else
X#endif
X	{
X		char ppath[128];
X
X		me[0] = '\0';	/* running on faxhost */
X		sprintf(ppath,"%s/%s",FAXLIB,FAXSERVER);
X		if ((ofp = popen(ppath, "w")) == NULL)
X		{
X			fprintf(stderr,"can't pipe to %s {%d}\n",ppath,errno);
X			exit(1);
X		}
X		piped = TRUE;
X	}
X
X/* do something useful */
X
X	ac = spoolfax(me, pwentry->pw_name, ofp, faxfp, type);
X
X	if (piped)
X		pclose(ofp);
X#ifdef	NETWIDE_FAX
X	else close(s);
X#endif
X	if (save)
X		savefax((fname==NULL)?tmpname:fname);
X
X	if (tmpname[0])
X		unlink(tmpname);
X	exit(ac);
X}
X
Xspoolfax(host, user, outfp, infp, ftype)
Xchar *host, *user;
XFILE *outfp, *infp;
Xint ftype;
X{
X	char tmp[256];
X	int nread, i;
X
X	if (*host)
X		sprintf(tmp,"%s@%s",user,host);
X	else strcpy(tmp,user);
X
X#define	write_err()	fprintf(stderr,"can't spool fax {%d}\n",errno)
X
X	errno = 0;
X	if (fprintf(outfp,"user %s\n",tmp) == EOF)
X		return(write_err());
X	if (fprintf(outfp,"uid %d\n",getuid()) == EOF)
X		return(write_err());
X
X	if (fprintf(outfp,"now %d\n",now) == EOF)
X		return(write_err());
X	if (fprintf(outfp,"mail %d\n",mail) == EOF)
X		return(write_err());
X	if (fprintf(outfp,"type %d\n",ftype) == EOF)
X		return(write_err());
X	if (fprintf(outfp,"hires %d\n",hires) == EOF)
X		return(write_err());
X
X	if (fprintf(outfp,"font %s\n",(hpfont)?hpfont:"none") == EOF)
X		return(write_err());
X
X	if (fprintf(outfp,"retfax %s\n",(retfax)?retfax:"none") == EOF)
X		return(write_err());
X
X	fprintf(outfp,"#\n");	/* marker for spoolfax */
X
X	for (i=0; i<entries; i++)
X	{
X		if (fprintf(outfp,"phone %s",phone[i]) == EOF)
X			return(write_err());
X		if (ftao[i])
X		{
X			if (fprintf(outfp," :%s",ftao[i]) == EOF)
X				return(write_err());
X		}
X		fprintf(outfp,"\n");
X	}
X	if (fprintf(outfp,"data\n") == EOF)
X		return(write_err());
X
X	while ((nread = fread(tmp, 1, 256, infp)) > 0)
X		if (fwrite(tmp, 1, nread, outfp) != nread)
X			return(write_err());
X	fflush(outfp);
X	return(0);
X}
Xvoid breakread()
X{
X	broken = TRUE;
X}
X
XFILE *collect_msg()
X{
X	static FILE *fp;
X	int written, tty;
X
X	broken = written = 0;
X	signal(SIGINT, breakread);
X	siginterrupt(SIGINT, 1);	/* interrupt sys calls */
X
X	tty = isatty(fileno(stdin));
X	if (*home == '/' && *(home+1) == '\0')
X		strcpy(tmpname,"/.infax.XXXXXX");
X	else sprintf(tmpname,"%s/.infax.XXXXXX",home);
X	mktemp(tmpname);
X	if ((fp = fopen(tmpname, "w+")) == NULL)
X	{
X		fprintf(stderr,"can't create tmp file\n");
X		return(NULL);
X	}
X	while (fgets(io, 248, stdin) != NULL)
X	{
X		if (broken)
X		{
X			written = 0;
X			break;
X		}
X		if (io[0] == '.' && tty)
X			break;
X		else if (io[0] == '~' && io[1] == 'v' && tty)
X		{
X			fclose(fp);
X			edit(tmpname);
X			if ((fp = fopen(tmpname, "a+")) == NULL)
X			{
X				fprintf(stderr,"no tmp file ?\n");
X				return(NULL);
X			}
X			written = (int)ftell(fp);
X			fprintf(stderr,"(continue)\n");
X			continue;
X		}	
X		else if (io[0] == '~' && io[1] == 'p' && tty)
X		{
X			rewind(fp);
X			fprintf(stderr,"-------\nMessage contains:\n");
X			while (fgets(io, 248, fp) != NULL)
X				fputs(io, stderr);
X			fprintf(stderr,"(continue)\n");
X			fseek(fp, 0L, 2);
X			continue;
X		}
X		written += strlen(io);
X		fputs(io, fp);
X	}
X	fclose(fp);
X	if (broken || !written)
X	{
X		unlink(tmpname);
X		fprintf(stderr,"null message, not sent\n");
X		return(NULL);
X	}
X	if ((fp = fopen(tmpname, "r")) == NULL)
X	{
X		fprintf(stderr,"can't re-read your tmp file\n");
X		return(NULL);
X	}
X	return(fp);
X}
Xsavefax(infile)
Xchar *infile;
X{
X	time_t ca;
X	struct tm *tml, *localtime();
X	struct stat fred;
X	char FaxSent[256];
X	FILE *in, *sfp;
X
X	time(&ca);
X	tml = localtime(&ca);
X	++tml->tm_mon;		/* jan is often 0 */
X	
X	if (*home == '/' && *(home+1) == '\0')
X	{
X		strcpy(FaxSent, "/FaxSent");
X		sprintf(io,"/FaxSent/%s.%02d%02d%02d",
X			phone[0],tml->tm_year,tml->tm_mon,tml->tm_mday);
X	}
X	else
X	{
X		sprintf(FaxSent,"%s/FaxSent",home);
X		sprintf(io,"%s/FaxSent/%s.%02d%02d%02d",home,
X			phone[0],tml->tm_year,tml->tm_mon,tml->tm_mday);
X	}
X
X	if (stat(FaxSent, &fred) && mkdir(FaxSent, 0700))
X	{
X		fprintf(stderr,"no directory %s\n",FaxSent);
X		exit(1);
X	}
X	if (((sfp = fopen(io, "a")) == NULL)
X		|| ((in = fopen(infile, "r")) == NULL))
X	{
X		fprintf(stderr,"can't save your fax to %s in %s\n",
X			phone[0],io);
X		exit(1);
X	}
X	fprintf(sfp,"\n\nSPOOLED %02d.%02d.%2d %02d:%02d:%02d\n",
X		tml->tm_mday,tml->tm_mon,tml->tm_year,
X		tml->tm_hour,tml->tm_min,tml->tm_sec);
X
X	while (fgets(io, 250, in) != NULL)
X		fputs(io, sfp);
X	fclose(in);
X	fclose(sfp);
X}
Xedit(what)
Xchar *what;
X{
X	char *ed;
X
X	if ((ed = getenv("EDITOR")) == NULL)
X		ed = "/usr/ucb/vi";
X
X	sprintf(io, "%s %s\n",ed,what);
X	system(io);
X}
Xusage()
X{
X	char tmp[40];
X
X	puts("fax options:");
X	puts("-a\"for the attention of fred bloggs\"");
X	puts("-h   use high resolution");
X	puts("-f   use an hp ljet  compatible font");
X	puts("-n   send it now");
X	puts("-m   confirm result by mail when sent");
X	puts("-r   specify return fax no");
X	if (*home == '/' && *(home+1) == '\0')
X		strcpy(tmp, "/FaxSent");
X	else sprintf(tmp,"%s/FaxSent",home);
X	printf("-s   save message in %s/phoneno.date\n",tmp);
X	puts("if called without a file name, fax reads stdin");
X	exit(1);
X}
END_OF_FILE
  if test 14931 -ne `wc -c <'faxclient/fax.c'`; then
    echo shar: \"'faxclient/fax.c'\" unpacked with wrong size!
  fi
  # end of 'faxclient/fax.c'
fi
if test -f 'faxhost/spool.fax.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'faxhost/spool.fax.c'\"
else
  echo shar: Extracting \"'faxhost/spool.fax.c'\" \(14959 characters\)
  sed "s/^X//" >'faxhost/spool.fax.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <string.h>
X#include <time.h>
X#include <ctype.h>
X#include <unistd.h>
X
X#include "../faxconfig.h"
X
X/*
X	spool.fax
X
X	spool faxes,
X	read incoming jobs,
X	split into straight through jobs and jobs where that
X		need special handling due to "f.t.a.o. fred bloggs"
X	convert input -> pbm -> g3
X	if straight through jobs > 1 && phone_nos > 1,
X		split into batches of size (phone_nos/faxmodems)
X
X	this looks [and is] rather messy due to the last minute addition
X	of special treatment of those guys that doen't have their own
X	fax machine but want their fax addressed [marked] "for the
X	attention of whatever". The quick fix I made works, but
X	the resulting mess is barely understandable [to me, that is].
X
X	I'm gonna rework him as soon as there's some time - I probably
X	have to anyway when I add prettier file types. Currently
X	the only thing that works as advertised is files pushed through
X	texttopbm. spooling faxes with pbm files should work, but I haven't
X	had the time to test these [hey, I'm doing this in my spare time].
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
Xlong	xpos;
Xint	type, hires, pages, blah, mail;
Xchar	tmp_nam[256], user[80], retfax[80], font[256], Ftao[256];
Xchar	io[1024], Xfile[256], Dfile[256];
Xchar	oldname[256], newname[256], linkbase[256], linkto[256], dataname[256];
X#ifdef	JOBID
X	jobid[80];
Xstruct	tm *tml, *localtime();
X#endif
X
Xextern	int errno;
X
Xchk_config()
X{
X	FILE *cfg;
X	char buf[256];
X	int i;
X
X	sprintf(buf, "%s/fax.config", FAXLIB);
X	errno = 0;
X	if ((cfg = fopen(buf, "r")) == NULL)
X	{
X		unlink(Xfile);
X		unlink(Dfile);
X		fax_log(ERROR, "spool.fax: can't read %s\n",buf);
X		mailexit(user);
X	}
X	i = 0;
X	while (fgets(buf, 254, cfg) != NULL)
X	{
X		if (buf[0] == '#')
X			continue;
X		if (!strncmp(buf, "device", 6))
X			++i;
X	}
X	fclose(cfg);
X	return(i);
X}
X
Xmain()
X{
X	FILE *fp;
X	int nread, phones, tread, count, ftaofs;
X	time_t now;
X	char *ptr;
X
X	phones = count = ftaofs = tread = errno = 0;
X	user[0] = retfax[0] = font[0] = Ftao[0] = '\0';
X
X	if (chdir(FAXSPOOL))	/* quick one, job done */
X	{
X		fax_log(ERROR,"spool.fax: can't cd to %s\n",FAXSPOOL);
X		mailexit(FAXADMIN);
X	}
X
X	(void)time(&now);
X
X#ifdef	JOBID
X	tml = localtime(&now);
X	++tml->tm_mon;		/* jan is 0 */
X
X	sprintf(jobid, "%02d%02d-%d",tml->tm_mon,tml->tm_mday,getpid());
X#endif
X	sprintf(tmp_nam,"%s/X.faxXXXXXX",FAXSPOOL);
X	mktemp(tmp_nam);
X	strcpy(Xfile, tmp_nam);
X
X	if ((fp = fopen(tmp_nam, "w")) == NULL)
X	{
X		fax_log(ERROR,"spool.fax: can't create X.file\n");
X		mailexit(FAXADMIN);
X	}
X		
X	chmod(tmp_nam, FAXFMODE);
X
X	fprintf(fp,"spooled %ld\n",(long)now);
X	fprintf(fp,"tries %3d\n",0);
X
X	while (fgets(io, 254, stdin) != NULL)
X	{
X		if (!count)
X		{
X			if (io[0] == 'f')	/* font */
X			{
X				ptr = io;
X				while (*ptr && (!isspace(*ptr)))
X					++ptr;
X				++ptr;
X				if (strncmp(ptr, "none", 4))
X					strcpy(font, ptr);	/* else use default */
X			}
X			else if (io[0] == 'h')	/* hires */
X			{
X				ptr = io;
X				while (*ptr && (!isdigit(*ptr)))
X					++ptr;
X				hires = atoi(ptr);
X			}
X			else if (io[0] == 'm')	/* hires */
X			{
X				ptr = io;
X				while (*ptr && (!isdigit(*ptr)))
X					++ptr;
X				mail = atoi(ptr);
X			}
X			else if (io[0] == 'r')	/* return faxno */
X			{
X				ptr = io;
X				while (*ptr && (!isspace(*ptr)))
X					++ptr;
X				strcpy(retfax, ++ptr);
X			}
X			else if (io[0] == 't')	/* type */
X			{
X				ptr = io;
X				while (*ptr && (!isdigit(*ptr)))
X					++ptr;
X				type = atoi(ptr);
X			}
X			else if (io[0] == 'u' && (!user[0]))	/* user */
X			{
X				ptr = io;
X				while (*ptr && (!isspace(*ptr)))
X					++ptr;
X				strcpy(user, ++ptr);
X			}
X			else if (io[0] == '#')
X			{
X				xpos = ftell(fp);
X				count = TRUE;
X			}
X		}
X		else
X		{
X			if (io[0] == 'd')	/* data follows */
X				break;
X			else if (io[0] == 'p')	/* last minute fix */
X			{			/* forgot ftao for 1off faxes */
X				++phones;	/* added to faxconvert */
X				if ((ptr = strchr(io, ':')) != NULL)
X				{
X					ftaofs++;
X					strcpy(Ftao, (ptr+1));
X				}
X			}
X		}
X		fputs(io, fp);
X	}
X	sprintf(tmp_nam,"%s/D.faxXXXXXX",FAXSPOOL);
X	mktemp(tmp_nam);
X	strcpy(Dfile, tmp_nam);
X
X		/* make a note of D.file name in X.file */
X	fprintf(fp,"data %s\n",tmp_nam);
X	fflush(fp);
X	if (ferror(fp))
X	{
X		unlink(Xfile);
X		fax_log(ERROR,"spool.fax: can't write X.file\n");
X		mailexit(FAXADMIN);
X	}
X	fclose(fp);
X
X	if ((!user[0]) || (!phones))
X	{
X		unlink(Xfile);
X		fax_log(ERROR,"spool.fax: doesn't look like a fax job to me\n");
X		mailexit(FAXADMIN);
X	}
X
X	if ((fp = fopen(tmp_nam, "w")) == NULL)
X	{
X		unlink(Xfile);
X		fax_log(ERROR,"spool.fax: can't create D.file\n");
X		mailexit(user);
X	}
X	chmod(tmp_nam, FAXFMODE);
X
X	while ((nread = fread(io, 1, 256, stdin)) > 0)
X	{
X		tread += nread;
X		if (fwrite(io, 1, nread, fp) != nread)
X		{
X			unlink(Xfile);
X			fax_log(ERROR,"spool.fax: can't write D.file\n");
X			mailexit(user);
X		}
X	}
X	fflush(fp);
X	if ((!tread) || ferror(fp))	/* empty file ? */
X	{
X		unlink(Xfile);
X		unlink(Dfile);
X		fax_log(ERROR,"spool.fax: can't write D.file, rcvd bytes %d\n",tread);
X		mailexit(user);
X	}
X	fclose(fp);
X
X	if ((nread = fork()) < 0)
X	{
X		unlink(Xfile);
X		unlink(Dfile);
X		fax_log(ERROR,"spool.fax: can't fork to convert files\n");
X		mailexit(user);
X	}
X	else if (!nread)	/* child */
X	{
X		if (setpgrp(0,0))
X		{
X			fax_log(ERROR, "spool.fax: can't create new prgp\n");
X			mailexit(FAXADMIN);
X		}
X		if (setuid(geteuid()))
X		{
X			fax_log(ERROR, "spool.fax: can't setuid(geteuid())\n");
X			mailexit(FAXADMIN);
X		}
X		if (setgid(getegid()))
X		{
X			fax_log(ERROR, "spool.fax: can't setgid(getegid())\n");
X			mailexit(FAXADMIN);
X		}
X
X		if (!share_fax(Xfile,Dfile,phones,ftaofs))
X#ifndef	JOBID
X			fax_log(0, "spool.fax: user %s, %d pages, %d reciepient%c\n",
X				user, pages, phones, (phones > 1)?'s':' ');
X#else
X			fax_log(0, "spool.fax: jobid %s, user %s, %d pages, %d reciepient%c\n",
X				jobid, user, pages, phones, (phones > 1)?'s':' ');
X
X		if (mail)
X		{
X			sprintf(io,"echo \"the job id of your spooled fax is %s \" | mail %s",
X				jobid,user);
X			system(io);
X		}
X#endif
X
X	}
X	exit(0);
X}
Xshare_fax(xnam,dnam,phones,oneoffs)
Xchar *xnam,*dnam;
Xint phones, oneoffs;
X{
X	FILE *X, *x;
X	char name[256], io[1024], *head;
X	int i, split, batches, done, per_batch, devices;
X
X	/* split a job into packets 
X	   check for jobs with special headers [ftao], do separately,
X	   split the balance into packets so that load is distributed
X	   evenly between faxmodems
X	*/
X
X	devices = chk_config();	/* or dead */
X
X	if (phones == 1)	/* doesn't need much splitting */
X		return(faxconvert(xnam,dnam,0));
X	else Ftao[0] = '\0';	/* last minute fix, spoolfax is due for a rewrite */
X
X	if (oneoffs)		/* special handling */
X		phones -= xoneoffs(xnam,dnam);
X
X			/* integer divide of 7 faxes / 10 modems == 0 */
X	per_batch = max(1,(phones/devices));
X	errno = 0;
X	if ((X = fopen(xnam, "r")) == NULL)
X	{
X		fax_log(ERROR,"spool.fax: can't open X.file %s\n",xnam);
X		mailexit(user);
X	}
X	if ((head = malloc((int)xpos)) == NULL)
X	{
X		fax_log(ERROR,"spool.fax: can't allocate memory\n");
X		mailexit(user);
X	}
X	if (fread(head, 1, (int)xpos, X) != (int)xpos)
X	{
X		fax_log(ERROR,"spool.fax: can't read X.file %s\n",xnam);
X		mailexit(user);
X	}
X
X	for (done=batches=split=0;;)
X	{
X		if (done || (split == phones))
X			break;
X
X		sprintf(name, "%s%d",xnam,batches);
X		if ((x = fopen(name, "w")) == NULL)	/* buggered */
X		{					/* rm all batches */
Xbuggered:
X			for (i=0; i<batches; i++)		/* but leave main job */
X			{				/* for manual cleanup */
X				sprintf(name, "%s%d",xnam,i);
X				unlink(name);
X			}
X			unlink(xnam);
X			unlink(dnam);
X			fax_log(ERROR,"spool.fax: serious problems during split %s\n",xnam);
X			mailexit(user);
X		}
X
X		chmod(name, FAXFMODE);
X		if (fwrite(head, 1, (int)xpos, x) != (int)xpos)
X			goto buggered;
X
X		for (i=0; i<per_batch; )
X		{
X			if (fgets(io, 256, X) == NULL)
X				goto buggered;
X			if (io[0] == '#' || (strchr(io, ':') != NULL))
X				continue;
X			if (!strncmp(io, "data", 4)) /* no more phone nos */
X			{
X				if (!i)
X					unlink(name);
X				done = 1;
X				break;
X			}
X			fputs(io, x);
X			++split;
X			++i;
X		}
X		fprintf(x,"data %s\n",dnam);
X		fflush(x);
X		if (ferror(x))
X			goto buggered;
X		fclose(x);
X		batches += (i > 0);
X	}
X	fclose(X);
X	unlink(xnam);	/* passed on simply as a "basename" */
X	return(faxconvert(xnam,dnam,batches));
X}
Xxoneoffs(xnam,dnam)
Xchar *xnam,*dnam;
X{
X	FILE *X, *D, *x, *d;
X	char ftao[128], newxnam[256], newdnam[256], txnam[256], tdnam[256],
X		*head, *ptr;
X	int split, nread;
X
X	errno = 0;
X	if ((D = fopen(dnam, "r")) == NULL)
X	{
X		fax_log(ERROR,"spool.fax: can't open D.file %s for ftao\n",dnam);
X		mailexit(user);
X	}
X	if ((X = fopen(xnam, "r")) == NULL)
X	{
X		fax_log(ERROR,"spool.fax: can't open X.file %s for ftao\n",xnam);
X		mailexit(user);
X	}
X		/* read header of X file */
X	if ((head = malloc((int)xpos)) == NULL)
X	{
X		fax_log(ERROR,"spool.fax: can't allocate memory\n");
X		mailexit(user);
X	}
X	if (fread(head, 1, (int)xpos, X) != (int)xpos)
X	{
X		fax_log(ERROR,"spool.fax: can't read X.file %s for ftao\n",xnam);
X		mailexit(user);
X	}
X
X	split = 0;	/* find jobs with phone 1234 :f.t.a.o fred */
X	sprintf(txnam,"%s/X.fxXXXXXX",FAXSPOOL);
X	mktemp(txnam);
X	sprintf(tdnam,"%s/D.fxXXXXXX",FAXSPOOL);
X	mktemp(tdnam);
X
X	while (fgets(io, 256, X) != NULL)
X	{
X		if (io[0] == '#' || ((ptr = strchr(io, ':')) == NULL))
X			continue;
X
X		sprintf(newxnam, "%s%d", txnam,split);
X		errno = 0;
Xbuggered:
X		if ((x = fopen(newxnam, "w")) == NULL)
X		{
X			fax_log(ERROR,"spool.fax: can't create %s for load sharing\n",newxnam);
X			mailexit(user);
X		}
X		chmod(newxnam, FAXFMODE);
X
X		if (fwrite(head, 1, (int)xpos, x) != (int)xpos)
X			goto buggered;
X
X		strcpy(ftao, (ptr+1));	/* save whats after ptr */
X		*ptr = '\0';		/* zero out at ':' */
X
X		/* io now contains just the phone number */
X		/* ftao contains now "f.t.a.o. fred" */
X
X		/* make new data name */
X		sprintf(newdnam,"%s%d", tdnam,split);
X
X		fprintf(x,"%s\ndata %s\n",io,newdnam);
X		fflush(x);
X		if (ferror(x))
X			goto buggered;
X		fclose(x);
X
X		errno = 0;
X		if ((d = fopen(newdnam, "w")) == NULL)
X			goto buggered;
X		chmod(newdnam, FAXFMODE);
X
X		fprintf(d,"%s\n",ftao);	/* make this part of the fax file */
X
X					/* add the balance */
X		while ((nread = fread(io, 1, 1024, D)) > 0)
X			fwrite(io, 1, nread, d);
X		fflush(d);
X		if (ferror(d))
X			goto buggered;
X		fclose(d);
X		faxconvert(newxnam, newdnam, 0);	/* or die */
X		++split;
X		rewind(D);
X	}
X	fclose(X);
X	fclose(D);
X	free(head);
X	return(split);
X}
Xfaxconvert(xn, dn, batches)
Xchar *xn, *dn;
Xint batches;
X{
X	int j, batch;
X	char scratchbuf[256], tmp[256], *ptr;
X	FILE *p, *fp;
X
X	/* do D.files [data] first, if they're ok, do Xfiles */
X	/* sendfax scans directory for x.files only */
X	/* in case of multiple batches convert data once, then make links */
X
X	batch = 0;
X	do	/* at least once */
X	{
X		if (!batch)	/* first time around */
X		{
X			strcpy(oldname, dn);
X			strcpy(newname, dn);
X			ptr = strrchr(newname, '/');
X			*(ptr+1) = 'd';
X			strcpy(linkto, newname);
X			strcat(newname, "0");
X			strcpy(linkbase, newname);
X
X				/* strip newlines */
X			if ((ptr = strchr(font, '\n')) != NULL)
X				*ptr = '\0';
X			if ((ptr = strchr(user, '\n')) != NULL)
X				*ptr = '\0';
X			if ((ptr = strchr(retfax, '\n')) != NULL)
X				*ptr = '\0';
X
X			switch(type)
X			{
X			case ASCII:
X				errno = 0;
X				if ((fp = fopen(oldname, "r")) == NULL)
X				{
X					fax_log(ERROR,"spool.fax: can't read textfile %s for conversion\n",oldname);
X					mailexit(user);
X				}
X				sprintf(scratchbuf,"%s/texttopbm %s %s%s -o%s.pbm",
X					LOCALBIN,
X					(hires)?"-h":"",
X					(font[0])?"-f":"",
X					(font[0])?font:"",
X					newname);
X
X				if ((p = popen(scratchbuf, "w")) == NULL)
X				{
X					fax_log(ERROR,"spool.fax: can't pipe to texttopbm with %s\n",scratchbuf);
X					mailexit(user);
X				}
X
X				if (Ftao[0]) /* make this part of the fax file */
X					fprintf(p,"%s\n",Ftao);
X				fprintf(p,"fax from %s",user);
X				if (strncmp(retfax, "none", 4))
X					fprintf(p,", fax # %s - ",retfax);
X				else fputc(' ',p);
X				timestamp(p,(time_t)0L);
X
X				fprintf(p,"\n\n");
X
X				while (fgets(scratchbuf, 254, fp) != NULL)
X					fputs(scratchbuf, p);
X
X				fflush(p);
X				if (ferror(p))
X				{
X					fax_log(ERROR,"spool.fax: can't unplump from texttopbm with %s\n",scratchbuf);
X					mailexit(user);
X				}
X				pclose(p);
X				fclose(fp);
X				unlink(oldname);	/* rm text input file */
X
X					/* have one or more pbm files now */
X				for (pages=0;;pages++)
X				{
X					sprintf(tmp, "%s.pbm.%d",newname,pages);
X					if (access(tmp, R_OK))
X						break;
X					sprintf(scratchbuf,"%s/pbmtog3 -s <%s >%s.g3.%d",LOCALBIN,tmp,newname,pages);
X					if (system(scratchbuf))
X					{
X						fax_log(ERROR,"spool.fax: can't execute pbmtog3 with %s\n",scratchbuf);
X						mailexit(user);
X					}
X					unlink(tmp);	/* get rid of pbm file */
X					sprintf(tmp, "%s.g3.%d",newname,pages);
X					chmod(tmp, FAXFMODE);
X				}
X				strcpy(dataname, linkbase);
X				break;
X
X			case PBM:
X				sprintf(scratchbuf,"pbmtog3 -s <%s >%s.g3.0",oldname,newname);
X				errno = 0;
X				if (system(scratchbuf))
X				{
X					fax_log(ERROR,"spool.fax: can't execute pbmtog3 with %s\n",scratchbuf);
X					mailexit(user);
X				}
X				unlink(oldname);	/* again: get rid of pbm file */
X				sprintf(tmp,"%s.g3.0",newname);
X				chmod(tmp, FAXFMODE);
X				pages = 1;
X				strcpy(dataname, newname);
X				break;
X			}
X		}
X		else
X		{
X			for (j=0; j<pages; j++)
X			{
X				sprintf(dataname,   "%s%d.g3.%d",linkto,batch,j);
X				sprintf(scratchbuf, "%s.g3.%d",linkbase,j);
X				if (link(scratchbuf, dataname))
X				{
X					fax_log(ERROR,"spool.fax: can't link %s to %s\n",linkbase,tmp);
X					mailexit(user);
X				}
X			}
X			sprintf(dataname, "%s%d",linkto,batch);
X		}
X
X
X				/* now do the X.file */
X		if (batches)	/* xn is basename only in case of batches */
X			sprintf(oldname, "%s%d", xn, batch);
X		else strcpy(oldname, xn);
X
X		strcpy(newname, oldname);
X		ptr = strrchr(newname, '/');
X		*(ptr+1) = 'x';
X		if ((p = fopen(oldname, "r")) == NULL)
X		{
X			fax_log(ERROR,"spool.fax: can't open %s after splitting D.files\n",oldname);
X			mailexit(user);
X		}
X		if ((fp = fopen(newname, "w")) == NULL)
X		{
X			fax_log(ERROR,"spool.fax: can't create new %s\n",newname);
X			mailexit(user);
X		}
X		chmod(newname, FAXFMODE);
X
X		while (fgets(scratchbuf, 126, p) != NULL)
X		{
X			if (!strncmp(scratchbuf, "data", 4))
X				fprintf(fp,"data %s\n",dataname);
X			else fputs(scratchbuf, fp);
X		}
X		fprintf(fp,"pages %d\n",pages);
X#ifdef	JOBID
X		fprintf(fp,"jobid %s\n",jobid);
X#endif
X		fflush(fp);
X		if (ferror(fp))
X		{
X			fax_log(ERROR,"spool.fax: can't write new %s\n",newname);
X			mailexit(user);
X		}
X		fclose(fp);
X		unlink(oldname);
X	} while (++batch < batches);
X
X	unlink(dn);
X	return(0);
X}
END_OF_FILE
  if test 14959 -ne `wc -c <'faxhost/spool.fax.c'`; then
    echo shar: \"'faxhost/spool.fax.c'\" unpacked with wrong size!
  fi
  # end of 'faxhost/spool.fax.c'
fi
if test -f 'sample.fax.aliases' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sample.fax.aliases'\"
else
  echo shar: Extracting \"'sample.fax.aliases'\" \(290 characters\)
  sed "s/^X//" >'sample.fax.aliases' <<'END_OF_FILE'
X# sample fax.aliases file
X# alias   phone no   ftao, starts with a colon	     optional comment
X#---------------------------------------------------------------------
Xfred    12345678   :for the attention of fred bloggs # comment
Xbill	98765
Xjoe	7654323	   :The Lady in Pink # should see her
END_OF_FILE
  if test 290 -ne `wc -c <'sample.fax.aliases'`; then
    echo shar: \"'sample.fax.aliases'\" unpacked with wrong size!
  fi
  # end of 'sample.fax.aliases'
fi
if test -f 'writefax.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'writefax.man'\"
else
  echo shar: Extracting \"'writefax.man'\" \(20046 characters\)
  sed "s/^X//" >'writefax.man' <<'END_OF_FILE'
X>From cat!fulcrum!ukc.ac.uk!mcsun.eu.net!mcsun.uucp!aimed!nick Thu Dec 13 15:41:13 1990
XReturn-Path: <cat!fulcrum!ukc.ac.uk!mcsun.eu.net!mcsun.uucp!aimed!nick>
XSubject: Re: writefax.man
XTo: klaus u schallhorn <klaus@cnix.uucp>
XDate: Wed, 12 Dec 90 16:49:33 EST
X>From: Nick Pemberton <aimed!nick>
XX-Mailer: ELM [version 2.3 PL6]
XSender: uucp.mcsun!aimed!nick@mcsun.eu.net
X	
X> I've just studied the document you posted to various newsgroups
X> and compared it to a document I received from a faxmodem
X> manufacturer, that asked me to sign a non disclosure agreement
X> in order to get what you posted.      ************************
X	
XThat sounds reasonably scary....
X	
X> 
X> Can you let me know the source of the document and if it's
X> "secret" as well or whether I've been done. I'd really like to know.
X
XI downloaded it from the Zoom Technologies BBS, at 1-617-451-5284. Zoom
Xare the folks who manufacture the modem - the chipset must be Sierra's.
X
XAs you can see from the document, there are no restrictive covenants
Xon it, and zoom never mentioned such restrictions. I'd question having to
Xsign such an agreement.
X
XNick.
X
X-- 
XNick Pemberton  		 uucp: !{lsuc, uunet!mnetor}!aimed!nick
XAIM, Inc			  bus: (416) 429-1085
XToronto, Ontario, Canada         Home: (416) 690-0647
X
X
X>From cat.fulcrum.bt.co.uk!uzi-9mm.fulcrum.bt.co.uk!axion!ukc!mcsun!sunic!uupsi!rpi!zaphod.mps.ohio-state.edu!wuarchive!cs.utexas.edu!utgpu!utzoo!mnetor!geac!aimed!nick Wed Dec 12 10:38:53 GMT 1990
XArticle: 112 of comp.dcom.modems
XXref: cnix alt.fax:79 comp.dcom.modems:112 comp.periphs:92
XPath: cnix!cat.fulcrum.bt.co.uk!uzi-9mm.fulcrum.bt.co.uk!axion!ukc!mcsun!sunic!uupsi!rpi!zaphod.mps.ohio-state.edu!wuarchive!cs.utexas.edu!utgpu!utzoo!mnetor!geac!aimed!nick
X>From: nick@aimed.UUCP (Nick Pemberton)
XNewsgroups: alt.fax,comp.dcom.modems,comp.periphs
XSubject: Here is WRITEFAX.MAN, details on ZOOM modem programming
XMessage-ID: <8658@aimed.UUCP>
XDate: 8 Dec 90 00:30:56 GMT
XOrganization: AIM, Inc, Toronto, Ontario
XLines: 496
X
XWell, after much waiting, dialing, etc, I finally have a copy of
XWRITEFAX.MAN, which is a guide to programming the ZOOM MX 2400S modem,
Xamongst others. I have had a number of requests for this file, so I
Xthought I'd post it (its not that large anyway....)
X
X------------snip----------snip--------snip---------
X 
X      SendFax Application Software Interface Specification Rev 2
X
X
X
XContents
X
X1.0    Introduction
X
X2.0    Physical interface
X
X3.0    Command set
X
X4.0    Data format
X
X5.0    Example sessions
X
X
X
X
X.pa
X.he       SendFax Application Software Interface Specification
X
X
X
X1.0    Introduction
X
XThis  document  defines the specifications  for  the  application 
Xsoftware interface to a PC Fax/Modem board incorporating Sierra's 
XSC11046, 2400 bps modem with Send only Fax at 4800 bps  (SendFax) 
Xchip.
X
XThe  device is intended to be used in internal cards for the  IBM 
XPC  or  compatible  computers or for  use  in  standalone  modems 
Xinterfacing to   any  computer using a standard RS232 port. 
X
XFunctions  and commands are defined to allow an extension to  Fax 
Xreceive mode in the future.
X 
XThe Fax/Modem board is designed such that it appears to the PC as 
Xa serial port.  The address of the board is user selectable to be 
Xone  of four ports, COM1, COM2, COM3 or COM4.  The  DCE  hardware 
Xmakes  and terminates calls, manages the  communications  session 
Xand  transmits  image  data in  accordance  with  the  procedures 
Xdefined  in the CCITT recommendation T.30.  The image data is  in 
Xmodified  Huffman  compressed format as described  in  the  CCITT 
Xrecommendation T.4.  
X
XThe  application  software running in the DTE  will  provide  the 
Xfunctions  of  user interface, conversion of user data  files  in 
Xvarious  formats  to fax format per CCITT T.4  specification  and 
Xtransfer  of  data  to the DCE for modulation  according  to  the 
Xprotocol defined in this document.
X
X 
X.pa
X
X
X
X2.0    Physical Interface
X
X2.1 Internal PC version
X
XThe  hardware  appears to the PC as a serial port at  an  address 
Xthat  is user selectable to be one of four ports.  Table 1  lists 
Xthe addresses and interrupt levels for various port selections.
X
XTo   the  application  software,  the  hardware  appears  as   an 
X8250/16450  type UART.  The application software writes or  reads 
Xdata  to  and  from registers in the UART.   Table  2  shows  the 
Xvarious registers and their addresses.  DTR and OUT2 bits in  MCR 
Xmust be set before communicating with the hardware.  The software 
Xsends  commands  and  data  to the hardware  by  writing  to  the 
Xtransmitter  holding  register (THR) in the UART.   Data  can  be 
Xwritten  to THR when THRE and/or TSRE bits in LSR are  set.    It 
Xreceives  responses  or  data from the hardware  by  reading  the 
Xreceive  buffer register (RBR).  Software should first check  the 
XLSR to see if DR bit is set indicating data is available in  RBR. 
XInterrupts  can  also  be  used  to  inform  the  software   that 
Xtransmitter is empty or data is available in the receiver.  Refer 
Xto  the  8250/16450  data sheet or the  IBM  technical  reference 
Xmanual  for more information on programming, reading and  writing 
Xto the UART.
X
X2.2 RS232 Standalone version
X
XThe UART in the SC11011 controller can be configured by  changing 
Xone  bit  (Bit3) in the code to present its serial  port  to  the 
Xoutside  world.   To enable the DTR control function,  the  AT&D2 
Xcommand must be issued befoer entering the fax mode. 
X
XThe  standard 2400 bps modem command set is extended for the  Fax 
Xapplication using a format of AT#F...  These commands were developed
Xin accordance with the original set proposed in the TIA T30 committee
Xin spring of 1989. Sierra is continuing to work with the T29.2 committee
Xto define teh ultimate standard command set for fax and data modems. 
X
XIn  the idle state the hardware is in  the  normal 2400  bps modem
Xmode.  The UART is programmed at speeds from  300 to 2400 bps to
Xcommunicate with the hardware. In the fax mode, the DTE is set to 19.2Kbps.
XFour  states  are defined to allow a clear understanding  of  the 
Xhardware control process:
X
X     1. Modem command mode:   AT commands accepted
X                              2400 bps max
X                              modem data mode entered online
X                              
X     2. Modem data mode:      +++ escapes to modem command mode
X                              2400 bps max
X
X     3. Fax command mode:     entered from modem command mode 
X                              with #F1
X                              19.2 kbps only
X                         
X     4. Fax data mode:        commands and data at 19.2kbps only
X                              return to fax command by:
X                                   sending command #F 
X                                   end of call/ call disconnect 
X                                   dropping DTR 
X
XAfter  power-up  the  hardware is in the normal  2400  bps  modem 
Xcommand mode.
X
XA  special command puts the hardware in the Fax mode.    Once  in 
Xthe  Fax  mode, the UART must be programmed for 19,200  bps  data 
Xrate, 8 bits and no parity.  This is because the image data  must 
Xbe  sent  to  the hardware at a rate that  is  faster  than  line 
Xtransmission  rate.   For 4800 bps synchronous transmission  line 
Xrate, the UART rate must be at least 9600 bps.  To allow for  the 
Xfuture accomodation of 9600 bps line transmission rate, the  UART 
Xspeed  in  Fax mode is fixed at 19,200 bps.   The UART  speed  is 
Xprogrammed by setting the DLAB bit in the modem control  register 
X(MCR)  and by writing appropriate values to the  divisor  latches 
XDLL  and  DLM.   Table 3 provides the DLL,  DLM  speed  selection 
Xvalues.    Flow  control  (XON/XOFF or RTS/CTS)  is  required  to 
Xsynchronize  the flow of information between the DTE and the  DCE 
Xduring image data transmission and HDLC frame reception.  In  the 
Xdata transmission mode, software must not send data when CTS  bit 
Xis  off  or  when <XOFF> is received.   Data can  be  sent  after 
Xreceiving <XON> or when CTS bit is set.
X  
X.pa
X
X
X
XTable 1.       COM port addresses
X
XCOM1   3F8 - 3FF    IRQ4
XCOM2   2F8 - 2FF    IRQ3
XCOM3   3E8 - 3EF    IRQ4
XCOM4   2E8 - 2EF    IRQ3
X
XTable 2.1       UART registers
X
XI/O decode (Hex)
XCOM1   COM2    COM3    COM4    R/W     DLAB    Register
X----------------------------------------------------------------
X3F8    2F8     3E8     2E8      W        0       THR        
X3F8    2F8     3E8     2E8      R        0       RBR          
X3F8    2F8     3E8     2E8     R/W       1       DLL
X3F9    2F9     3E9     2E9     R/W       1       DLM
X3F9    2F9     3E9     2E9     R/W       0       IER
X3FA    2FA     3EA     2EA      R        0       IIR
X3FB    2FB     3EB     2EB     R/W       0       LCR
X3FC    2FC     3EC     2EC     R/W       0       MCR
X3FD    2FD     3ED     2ED     R/W       0       LSR   
X3FE    2FE     3EE     2EE     R/W       0       MSR
X
XTable 2.2      Register bit defintions
X
XRegister       7     6     5     4     3     2     1     0
X---------------------------------------------------------------
XTHR            -------- TRANSMIT DATA (DLAB = 0) ---------
XRBR            -------- RECEIVE DATA  (DLAB = 0) ---------
XDLL            ---- DIVISOR LATCH LS BYTE (DLAB = 1) -----         
XDLM            ---- DIVISOR LATCH MS BYTE (DLAB = 1) -----
XIER            0    0     0      0    MSI   LSI  THRE   DA
XIIR            0    0     0      0     0    ID1   ID0   IP/
XLCR          DLAB   SB    SP    EPS   PEN   STB  WLS1  WLS0
XMCR            0    0     0    LOOP  OUT2  OUT1   RTS   DTR
XLSR            0   TSRE  THRE   BI    FE    PE    OR    DR
XMSR          RLSD   RI    DSR   CTS  DRLS  TERI  DDSR  DCTS  
X---------------------------------------------------------------
X
XTable 3.       Speed selection table 
X
XSPEED (BPS)    DLM (HEX)   DLL (HEX)
X----------------------------------------
X300               01          80
X1200              00          60
X2400              00          30
X4800              00          18
X9600              00          0C
X19200             00          06      
X----------------------------------------
X
X
X
X3.0    Command Set
X
XExtensions to the Hayes AT command set for Fax mode operation are 
Xdefined in this section.
X
XGeneral
X
X1) All extended commands start with the # prefix. This represents 
Xa  major  change  from previous versions  which  utilized  the  + 
Xprefix. The change was made to provide upward compatibility  with 
Xfuture  TIA command sets which are expected to use the +  symbol. 
XFor the immediate future, the firmware will accept either prefix.
X
X2)  All extended commands have only one alpha character  followed 
Xby a numeric value in the range of decimal 0 to 255.  Value 0 may 
Xbe omitted.
X
X3)  Fax mode assumes XON/XOFF or CTS flow control in  data  mode.  
X&D2 command must be issued for DTR controlled abort.
X
X4) Once the hardware enters the Fax mode, it  will remain in  Fax 
Xmode ( and accept commands at 19.2 kbps ) until one of  following 
Xoccurs :
X
X       a) software issues a #F request to return to command mode
X       b) a call disconnect frame is received
X       c) application software issues an abort by dropping DTR
X
XCOMMANDS
X
X
X#Bn     Speed control
X
X#B/B0   Reserved         
X#B1     Reserved
X#B2     Reserved for V.23
X#B3     Reserved for V.23
X#B4    Fax transmission speed of 2400 bps
X#B5     Fax transmission speed of 4800 bps
X#B6     Fax transmission speed of 7200 bps
X#B7     Fax transmission speed of 9600 bps
X
XThis  command is used to specify the initial speed at  which  the 
Xhardware will attempt to connect to the remote Fax machine.   For 
Xthe SC11046 based hardware this will normally be 4800 bps, so  B5 
Xcommand  will  be  used.  However, the user  at  his  option  can 
Xspecify a lower initial speed of 2400 bps by issuing B4.  If  the 
Xhigher  initial speed is specified, the hardware will attempt  to 
Xestablish connection at the higher speed and will fallback to the 
Xlower speed if unsuccessful.
X
X
X
X
X 
X
XEn     Received frame display format selection
X
XE/E0   Disable display of received HDLC frames
XE1     Display frame in binary format
XE2     Display frame in 2 digit ASCII Hex format
X
X
X
XFn     Mode control
X
XF/F0   Return to normal modem mode (300 to 2400 bps data rate)
XF1     Enter Fax mode (19,200 bps data rate)
X
X
XKn     DTE flow control
X
XK/K0   Disable flow control
XK3     Enable CTS flow control
XK4     Enable XON/XOFF flow control
X
XMn     Speaker Control
XM0     Speaker Always Off
XM1     Speaker Off after Connect Message
XM2     Speaker Always On
XM3     Speaker Off during Dial
X
XPn     Number of pages to be transmitted (n = 1 to 255)
X
X
XRn     Resolution control
X
XR/R0   Send document with normal resolution
XR1     Send document with fine resolution
X
X
XTn     Test modes
X
XT/T0   End test mode
XT1     Enter  test mode 1.  This mode is used to dial  a  remote       
X       Fax   machine  and  automatically  send  a  message   stored 
X       in EPROM.
X.pa
X
X
XFAX result codes
X
XDuring the Fax session the hardware will report the status of the 
Xcall with result codes.  An action by the software may or may not 
Xbe necessary depending on the response.
X
XAll the normal Hayes result codes will also be reported.
X
XVerbose                Digit   Usage
X
X
XCED                      a     Ansertone detected 
X
XCFR                      g     Remote machine confirmation to receive
X
XCONNECT 2400/FAX         w     Connection speed 2400 bps
X
XCONNECT 4800/FAX         x     Connection speed 4800 bps
X
XCONNECT 7200/FAX         y     Connection speed 7200 bps
X
XCONNECT 9600/FAX         z     Connection speed 9600 bps
X
XCRC ERROR                e     Error in received frame
X
XCRP                      c     Repeat request
X
XCSI                      -     Remote machine Identification
X
XDCN                      d     Disconnect
X 
XDIS                      b     Remote machine capabilities frame
X
XFTT                      f     Failure to train
X
XINVALID FRAME            i     Received frame is invalid
X
X MCF                      m     Message received OK
X
XRTN                      h     Message not received OK
X
XRTP                      j     Retrain positive
X.pa
X
X
X4.0    Data format
X
XThe  Transmit Subscriber Identification data encoded in the  T.30 
Xnegotiation  will be taken from the nvram location  Z3. 
X
X
XImage  data  will be in compressed format  with  one  dimensional 
Xcoding  rules  in accordance with the  CCITT  specification  T.4.  
XData will be coded assuming the receiving Fax machine is  capable 
Xof  a  scan time of 0 milliseconds per line.  Each line  of  data 
Xmust  terminate  with a minimum of 3 bytes of zeroes  before  the  
XEOL   sequence.  The  zeroes must be byte aligned.  The    software 
Xwill   detect  the zero  bytes at the end of each line  and  fill 
Xin  the  required   number   of zeroes  based  on  the  speed  of 
Xconnection  and the minimum scan time per  line specified by  the 
Xreceiving  Fax machine.  Data  must  be coded with MSB the  first 
Xbit   to  be  transmitted from DTE to modem.The modem sends the
Xdata LSB first to the phone line..    Transmission  of  data    
Xwill   be synchronized using flow control (XON/XOFF or CTS). After
Xsending the  last  byte of page data, software will  wait   for a
Xresponse  from the hardware before issuing a command  or  sending
Xdata  for the next page.
X
X5.0    Example sessions
X
XIn  the  following  example sessions, the  response  is  enclosed 
Xwithin  <> brackets.  The defaults are B3 (4800 bps), P1  (single 
Xpage), R0 (normal resolution) and T0 (no test mode).    
X
XEach  command line terminates with a CRLF, a response begins  and 
Xterminates with a CRLF.
X
Xi) Send 1 page of document with normal resolution
X
XCommand                       Response
X
XATX4&D2#B3#P1#R0#T0#F1        <OK>      ; Enter Fax mode
X                              <XOFF> CTS -> 0
X
XATDT4082639337                <OK>      ; Dial a Fax machine
X                                        ; any AT response valid
X                              <CED>
X                                        ;  Answertone detected
X
X                              <CSI = 408 263 1234>
X                                        ; Called machine 
X                                        ; identification
X                              <DIS>
X                                        ; Capabilities 
X                                        ; frame received
X
X                              <CFR>
X                                        ; OK to send page data
X
X                              <CONNECT 4800/FAX>
X                                        ; Connection speed
X   
X                              <XON>  CTS -> 1
X                                        ; Page 1 data is sent 
X                                        ; using flow control
X---DATA--SENT---
X                              <XOFF> CTS -> 0
X---DATA STOPPED---
X                              <XON>  CTS -> 1
X---DATA--SENT---
X                                        ; No more data for page 1
X                                        ; tx underflow
X
X                              <XOFF> CTS -> 0
X                              <MCF>
X                                        ; Page 1 transmission OK
X          
X                              <NO CARRIER>
X                                        ; Call terminated, return to 
X                                        ; command mode
X
Xno new commands 
Xuntil here
Xii) Send 2 pages of document with normal resolution
X
XCommand                       Response                          
X
XATX4&D2#B3#P2#R0#T0#F1                  ; Enter Fax mode
X                              <XOFF> CTS -> 0
X                              <OK>
X
XATDT4082639337                <OK>      ; Dial a Fax machine
X                                        ; any AT response valid
X                              <CED>
X                                        ; Answertone detected
X
X                              <INVALID FRAME> 
X                                        ; Received frame invalid
X
X                              <CSI = 408 263 1234>
X                                        ; Called machine 
X                                        ; identification
X
X                              <DIS>
X                                        ; Capabilities 
X                                        ; frame received
X
X
X                              <CFR>
X                                        ; OK to send page data
X                
X                              <CONNECT 4800/FAX>
X                                        ; Connection speed
X
X                              <XON>  CTS -> 1
X                                        ; Page 1 data is sent
X                                        ; using flow control
X---DATA--SENT---
X                              <XOFF> CTS -> 0
X---DATA STOPPED---
X                              <XON>  CTS -> 1
X---DATA--SENT---
X                                        ; No more data for page 1
X                                        ; tx underrun
X                              <XOFF> CTS -> 0
X                              <MCF>
X                                        ; Page 1 transmission OK
X                                        
X                              <XON>  CTS -> 1
X                                        ; Page 2 Data is sent
X                                        ; using flow control
X---DATA--SENT---
X                              <XOFF> CTS -> 0
X---DATA STOPPED---
X                              <XON>  CTS -> 1
X---DATA--SENT---
X                                        ; No more data for page 2
X                                        ; tx underrun
X
X                              <XOFF> CTS -> 0
X                              <MCF>
X                                        ; Page 2 transmission OK
X                              <NO CARRIER>
X                                        ; Call terminated, return to 
X                                        ; command mode 
Xno new commands 
Xuntil here
X
X-- 
XNick Pemberton  		 uucp: !{lsuc, uunet!mnetor}!aimed!nick
XAIM, Inc			  bus: (416) 429-1085
XToronto, Ontario, Canada         Home: (416) 690-0647
X
X
END_OF_FILE
  if test 20046 -ne `wc -c <'writefax.man'`; then
    echo shar: \"'writefax.man'\" unpacked with wrong size!
  fi
  # end of 'writefax.man'
fi
echo shar: End of archive 3 \(of 5\).
cp /dev/null ark3isdone
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.