home *** CD-ROM | disk | FTP | other *** search
- Subject: v24i039: Email fax-sending package, Part01/05
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: 0c8fe16e 6f072551 39bbea94 42baa701
-
- Submitted-by: klaus u schallhorn <cnix!klaus>
- Posting-number: Volume 24, Issue 39
- Archive-name: faxpax/part01
-
- This is faxpak [Copyright (C) 1991 klaus schallhorn,
- klaus@cnix.uucp]
-
- faxpak currently runs on Suns only - not because it uses any spe-
- cial SunOs features, but because I don't have access to anything
- else. I developed faxpak mainly on a 4/60, then moved it to a
- 3/60 that does all our spooling.
-
- Apart from [temporary] hardware and typeface restrictions [see
- below] faxpak is quite flexible. It allows faxes to be sent from
- any networked machine. It allows aliases and distribution lists.
- Entries in such lists needing a special "for the attention of"
- string are forked out as separate jobs. If you have more than 1
- fax modem, faxpak automatically shares the load between these
- modems. This includes splitting of batches to distribution lists
- into several queues.
-
- faxpak enforces permissions. You can set faxpak up to send local
- faxes any time, long distance ones and international ones to be
- sent at cheap rates only. You can enforce the sending of faxes to
- any given phone number at fixed times. And you can permit some
- users to override these time restrictions.
-
- faxpak was created when the post office increased our contract
- postage rates to an almost insane level. We therefore decided [as
- a small publishing house] to deliver our newsletter by other
- means. We now deliver by mail(1) to subscribers' mailboxes at
- various online and video text systems, we allow direct modem con-
- nection to mbox [our 3/60] and we fax our newsletter.
-
- faxpak is used for oneoff faxes [and only if I can't email], and
- has been used three times [we publish every other week] for
- batches of ~150 faxes @ five pages each to our subscriber list.
- Batches of this size take a good two nights to send out, although
- the pure transmission time is just under 12 hours [the rest is
- engaged phone lines, repeats because transmission errors, logins
- sneaking in on the faxmodems, etc].
-
- faxpak currently supports touchbase's 2496 fax modem and others
- that use or emulate the sierra type fax chipset, such as zoom's
- mx 2400s. Early december I found someone willing and supposedly
- able to ship a beta class2 modem. Unfortunately it seems to have
- been sent by bicycle. It's supposed to be here "real soon now".
-
- For this reason faxpak does [not yet] support other modems, nor
- does it allow incoming faxes.
-
- #! /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: MANIFEST faxclient faxhost faxhost/faxcleanup.c
- # faxhost/faxfonts faxhost/wiring.c
- # Wrapped by rsalz@litchi.bbn.com on Wed Mar 13 14:08:00 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 1 (of 5)."'
- if test -f 'MANIFEST' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'MANIFEST'\"
- else
- echo shar: Extracting \"'MANIFEST'\" \(1250 characters\)
- sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
- X File Name Archive # Description
- X----------------------------------------------------------
- XMANIFEST 1 This shipping list
- XFaxConfig 2 chmod +x or sh FaxConfig
- XHowto.Install 5 basic install info
- XReadme 4 describes faxpak
- Xfaxclient 1
- Xfaxclient/fax.c 3 user interface [wot - no vindohs?]
- Xfaxhost 1
- Xfaxhost/faxcleanup.c 1 leftover disposer
- Xfaxhost/faxfonts 1 kit to roll your own 8bit charset
- Xfaxhost/faxfonts/diy_codep861.def 5
- Xfaxhost/faxfonts/diy_ibmpc.def 5
- Xfaxhost/faxfonts/diy_iso.def 5
- Xfaxhost/faxfonts/diykit.c 2
- Xfaxhost/faxfonts/diykit.h 4
- Xfaxhost/faxfonts/hires.uue 4 compressed font data
- Xfaxhost/faxfonts/lores.uue 4 same
- Xfaxhost/faxlog.c 5
- Xfaxhost/fntwrite.c 4
- Xfaxhost/pbmtog3.c 4 REPLACE pbmplus/pbmtog3 WITH THIS ONE !
- Xfaxhost/sendfax.c 2
- Xfaxhost/sierracmd.h 4
- Xfaxhost/spool.fax.c 3 spooler
- Xfaxhost/texttopbm.c 5 uses the diy font kit
- Xfaxhost/wiring.c 1
- Xsample.dot.faxrc 5 free samples
- Xsample.fax.aliases 3
- Xsample.fax.list 4
- Xwritefax.man 3 tech specs for sierra type modems
- END_OF_FILE
- if test 1250 -ne `wc -c <'MANIFEST'`; then
- echo shar: \"'MANIFEST'\" unpacked with wrong size!
- fi
- # end of 'MANIFEST'
- fi
- if test ! -d 'faxclient' ; then
- echo shar: Creating directory \"'faxclient'\"
- mkdir 'faxclient'
- fi
- if test ! -d 'faxhost' ; then
- echo shar: Creating directory \"'faxhost'\"
- mkdir 'faxhost'
- fi
- if test -f 'faxhost/faxcleanup.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'faxhost/faxcleanup.c'\"
- else
- echo shar: Extracting \"'faxhost/faxcleanup.c'\" \(5045 characters\)
- sed "s/^X//" >'faxhost/faxcleanup.c' <<'END_OF_FILE'
- X#include <stdio.h>
- X#include <sys/time.h>
- X#include <dirent.h>
- X
- X#include "../faxconfig.h"
- X
- Xstruct FAX fax;
- Xchar io[512], tmp[256];
- Xtime_t now;
- Xint maxage, maxtry, blah;
- X
- X/*
- X faxcleanup
- X
- X runs once a day to rm old garbage that might be left over.
- X all the functions here are really shortened stubs picked
- X mostly from sendfax.c [I plan to do a faxlib later].
- X
- X first released version 0.99 [desperado version]
- X cleaned up Jan 28nd '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
- Xread_config()
- X{
- X FILE *cfg;
- X char a[256], b[80];
- X int i;
- X
- X maxage = maxtry = 0;
- X sprintf(a, "%s/fax.config", FAXLIB);
- X if ((cfg = fopen(a, "r")) == NULL)
- X {
- X fax_log(ERROR,"faxcleanup: 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 %s",a,b) < 1))
- X continue;
- X if (!strcmp(a, "maxage"))
- X maxage = atoi(b);
- X else if (!strcmp(a, "maxtry"))
- X maxtry = atoi(b);
- X if (maxage && maxtry)
- X break;
- X }
- X fclose(cfg);
- X return(0);
- X}
- Xread_job(fp, xn)
- XFILE *fp;
- Xchar *xn;
- X{
- X int i;
- X
- X if (getint(fp,&fax.spooled)) /* spool timestamp */
- X return(ERROR);
- 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 || getstring(fp,tmp) /* type, don't need to know */
- X || getint(fp,&fax.hires)/* hires, NEEDED FOR SENDFAX */
- X || getstring(fp,tmp) /* font, don't need to know */
- X || getstring(fp,tmp)) /* retfax, don't need to know */
- X return(ERROR);
- X if ((fax.phone_nos = getphone(fp)) <= 0)
- 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 char phone[80];
- X long oldpos;
- X
- X for (;;)
- X {
- X oldpos = ftell(fp);
- 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 return(TRUE);
- X}
- Xmain()
- X{
- X DIR *dirp;
- X struct dirent *dp;
- X FILE *fp, *pp;
- X time_t days;
- X char me[80];
- X
- X blah = 0;
- X if (chdir(FAXSPOOL)) /* quick one, job done */
- X {
- X fax_log(ERROR,"faxcleanup: can't cd to FAXSPOOL\n");
- X exit(1);
- X }
- X if (read_config())
- X exit(1);
- X
- X days = (60L * 60L * 24L); /* about an average unix working day */
- X days *= (time_t)maxage;
- X now = time((time_t *)NULL);
- X
- X if (gethostname(me, 80))
- X me[0] = '\0';
- X
- X if ((dirp = opendir(FAXSPOOL)) == NULL)
- X {
- X fax_log(ERROR,"faxcleanup: can't open directory %s\n",FAXSPOOL);
- X exit(1);
- X }
- X
- X while ((dp = readdir(dirp)) != NULL)
- X {
- X if (strncmp(dp->d_name, "x.f", 3))
- X continue;
- X
- X if ((fp = fopen(dp->d_name, "r")) == NULL)
- X {
- X fax_log(ERROR,"faxcleanup: can't open %s\n",dp->d_name);
- X exit(1);
- X }
- X if (read_job(fp, dp->d_name))
- X {
- X fax_log(ERROR,"faxcleanup: can't read %s\n",dp->d_name);
- X exit(1);
- X }
- X if ((fax.spooled + days < now) || fax.tries >= maxtry)
- X {
- X rewind(fp);
- X sprintf(io, "mail %s",fax.user);
- X if ((pp = popen(io, "w")) == NULL)
- X {
- X fax_log(ERROR,"faxcleanup: can't mail user %s about bad job %s\n",
- X fax.user,dp->d_name);
- X exit(1);
- X }
- X#ifdef JOBID
- X fprintf(pp,"your fax job %s, queued ",fax.jobid);
- X#else
- X fprintf(pp,"your fax job %s, queued ",dp->d_name);
- X#endif
- X timestamp(pp, (time_t)fax.spooled);
- X fprintf(pp,"could not be sent\n\n");
- X fprintf(pp,"no of attempts and unsent phone nos:\n");
- X
- X while (fgets(io, 128, fp) != NULL)
- X {
- X if ((!strncmp(io, "phone", 5))
- X || (!strncmp(io, "tries", 4)))
- X fprintf(pp, "\t%s",io);
- X }
- X fprintf(pp,"\n");
- X
- X fprintf(pp,"you can ask %s for the appropriate logs\n\n",FAXADMIN);
- X fprintf(pp,"regrettably yours\n\n\tfaxcleanup%c%s\n\n",
- X (me[0])?'@':' ',me);
- X fprintf(pp,"PS: have you considered using email ?\n");
- X fflush(pp);
- X if (ferror(pp))
- X {
- X fax_log(ERROR,"faxcleanup: can't mail user %s about bad job %s\n",
- X fax.user,dp->d_name);
- X exit(1);
- X }
- X pclose(pp);
- X fclose(fp);
- X rmjob(fax.xname, fax.dname, fax.pages);
- X }
- X }
- X closedir(dirp);
- X exit(0);
- 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 5045 -ne `wc -c <'faxhost/faxcleanup.c'`; then
- echo shar: \"'faxhost/faxcleanup.c'\" unpacked with wrong size!
- fi
- # end of 'faxhost/faxcleanup.c'
- fi
- if test ! -d 'faxhost/faxfonts' ; then
- echo shar: Creating directory \"'faxhost/faxfonts'\"
- mkdir 'faxhost/faxfonts'
- fi
- if test -f 'faxhost/wiring.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'faxhost/wiring.c'\"
- else
- echo shar: Extracting \"'faxhost/wiring.c'\" \(41916 characters\)
- sed "s/^X//" >'faxhost/wiring.c' <<'END_OF_FILE'
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <termios.h>
- X#include <fcntl.h>
- X#include <errno.h>
- X#include <signal.h>
- X#include <sys/time.h>
- X
- X#include "../faxconfig.h"
- X
- X
- Xextern int errno;
- X
- X/*
- X wiring.c
- X
- X first released version 0.99a [desperado version]
- X cleaned up Feb 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
- X faxpak is late by about 6 weeks. It turned out that the way
- X the faxmodem communicates with the host is extremely, well,
- X artistic. It also turned out that g3 files, as specified
- X in the ccitt specs need quite a bit of processing before
- X they can be stashed down the serial port.
- X
- X The faxmodem basically makes the assumption it's running
- X on a medium to fast dos box. It assumes it has the undivided
- X attention of the host, and it assumes it can fiddle with
- X the actual wiring between the host and the modem at will
- X [like the guy in the movie trying to start a stolen car].
- X
- X If, for instance, you're using hardware flow ctl, the
- X fax modem still sends tons of xon's/xoff's although you
- X specified NOT to use xonoff.
- X
- X pauses of more than one fifteenth of a second during the
- X tx [transmission] phase of a fax result in a quiet abort.
- X The faxmodem regards this as "end of page" and squirts
- X abuse to the fax machine at the other end.
- X
- X Imagine news expiring a full feed, or processing an incoming
- X batch, and the standard cron tab entry finding old garbage
- X and removing it and you can see that a delay of something
- X like 60 or 70 milliseconds is quite possible.
- X
- X I therefore suggest not to schedule any faxes at or
- X around the time disk intensive cron jobs are due if you cannot
- X guarantee there won't be any major swapping.
- X
- X A 3/60 handles concurrent "find", or "newsrun" and faxes ok.
- X Copying a few Mb via nfs while your sending multiple faxes works
- X as well.
- X
- X On a 10 mhz 286 [dos] box printf statements while transmitting
- X can screw you up [actually not you, but the outgoing fax].
- X They take too long. And I'm not kidding.
- X
- X I assume "Flow control" is done partly in rs232 fashion,
- X more so according to what's possible and common on dos boxes.
- X In fact, the various modem manufacturers' specs specify which
- X bit in which register to twiddle, in the dos box hardware,
- X rather than how to connect to a serial port.
- X
- X This proves to have no effect - unless the fax modem is
- X actually connected to a dos box.
- X
- X In the course of getting this to work I have used three rolls
- X of fax paper, resorted to beating the fax modem [makes you
- X feel real good. Doesn't advance the issue though], and missed some
- X of my favourite tv pgms.
- X
- X After some persistant phone calls to the vendor I even
- X discovered that my modem had beta release firmware [no hint of that
- X in the sales blurb or the tech specs]. A "pre release" prom was
- X promised and arrived promptly after a week [I actually got two].
- X Clearly labelled "BETA RELEASE" this time. I would
- X not be surprised to find further discrepancies between specs
- X and real life [incorporated into the wiring, 26.1.90].
- X
- X Well, at least it works now, on Sun 3's and Sun 4's [I run 4.1],
- X using hardware flow ctl - no chance with xon/xoff.
- X
- X If you don't have a Sun, and cannot yet get your hands on one
- X of these "available real soon now" class2 modems [I'm still waiting],
- X I suggest you get a fax modem
- X
- X ON LOAN, or
- X =======
- X ON APPROVAL,
- X ===========
- X
- X and have the supplier [remember, it's not a vendor yet] confirm
- X that the modem's command set adheres strictly to the CCITT T.30
- X specifications [dubbed sierra], as outlined in the enclosed
- X document "writefax.man" which I picked up on the net.
- X
- X There are faxmodems out and available now that currently
- X support T.30 *and* some proprietary command set [often using
- X a binary language when analysed with a serial port sniffer].
- X Some faxmodems come with a non standard command set and need
- X an upgrade in firmware to make them t.30 compatible [like the
- X ones I used]. Others will be relaunched as t.30 compatible ones,
- X again, "real soon now" [honestly, I'm running beta].
- X
- X You have to make sure though that the modem recognises AT LEAST
- X the sierra, or t.30, standard - class2 type modems of course
- X would be far better, but as far as I know the standard is still
- X in the making. The making of the modems thusly might take just
- X that little bit extra.
- X
- X I'm not trying to discourage you.
- X
- X I just want to make sure you don't run out and buy yourself
- X a fax modem you can only use with the vendors software on a dos
- X box [why don't you use email anyway?].
- X
- X Only after you've aquired a fax modem on the terms outlined
- X here should you play with this module with:
- X
- X#define TESTING
- X#define TEST_DEVICE=\"/dev/whatever_device_is_handy_for_testing\"
- X
- X to get it working. And only if you get it to work on your system,
- X is faxpak a make, install 'n run package.
- X
- X During development it's certainly helpful to turn incoming
- X getty's OFF. Otherwise you might have to reboot because
- X an aborted attempt might block the port from further use.
- X
- X If the modem works to your satisfaction for several years
- X you may pay the bill for the modem.
- X
- X It is possible that I have to port this within the next six to
- X eight weeks to a xenix 286 box - a system I know nothing of.
- X But I won't know this for sure until early march.
- X
- X*/
- X
- X#ifdef SIERRA
- X/*
- X sierra modems cannot digest raw group 3 format fax files. They
- X need quite a bit of munging and processing.
- X*/
- X#include "sierracmd.h"
- X#endif SIERRA /* ***************************************************** */
- X
- X
- X
- X#ifdef CLASS2
- X while (class2 modem != yet arrived)
- X ;
- X#endif
- X
- X
- X
- X
- X
- X
- X/* *************** these apply to both types of modem types ************ */
- X#define Class2 0
- X#define Sierra 1
- X
- Xstruct Modems
- X{
- X char *name;
- X int type;
- X} known_modems[]=
- X{
- X "class2", Class2, /* your best bet */
- X "sierra", Sierra /* see above, and sierracmd.h for info */
- X};
- X#define MAX_MODEM (sizeof(known_modems)/sizeof(struct Modems))
- X
- Xstruct termios virgin, wire;
- X
- Xint ser_port, cannot, dev_no, curjob, curpage, sent, failed,
- X dial_tries;
- Xstatic int foul;
- X
- Xchar wbuf[1024], biff[1024], namebuf[256];
- Xchar devnam[256], lcknam[256];
- Xunsigned char rxbuf[1024], txbuf[2048];
- XFILE *logfp;
- X
- Xvoid breakwrite();
- Xchar *faxtime();
- X
- X
- X#ifndef TESTING
- X#define SPEAKER 0
- X#define FUNCTION(funcname) ""
- X
- Xextern char **Devices, **Devlocks, **Faxtypes, **Wakeup,
- X *Dialtyp, *Topspeed;
- Xextern struct FAX fax;
- Xextern int blah;
- X
- X#else /* ******************** TESTING ********************* */
- X
- X#include <varargs.h>
- X#ifndef SPEAKER
- X#define SPEAKER 2
- X#endif
- X#define FUNCTION(funcname) funcname
- X
- Xchar tstphone[80], faxtype[80], wakeup[2], dev[80];
- Xchar *Devices[2], *Devlocks[2], *Faxtypes[2], *Wakeup[2],
- X Dialtyp[2], Topspeed[2];
- Xstruct FAX fax;
- Xint blah=9;
- X
- Xmain(ac,av)
- Xint ac;
- Xchar *av[];
- X{
- X if (ac != 4)
- X {
- X fprintf(stderr,"need phoneno, no_of_pages, g3.basename\n");
- X exit(1);
- X }
- X strcpy(fax.user, "root"); /* you need the perms for port access anyway */
- X strcpy(fax.dname, av[3]);
- X strcpy(fax.xname, "nosuch");
- X strcpy(tstphone, av[1]);
- X fax.phone = (char **)malloc(2*sizeof(char*));
- X fax.phone[0] = tstphone;
- X fax.phone[1] = NULL;
- X fax.tries = fax.uid = 0;
- X fax.now = TRUE;
- X fax.mail = 0;
- X fax.pages = atoi(av[2]);
- X fax.phone_nos = 1;
- X#ifdef SIERRA
- X strcpy(faxtype, "sierra");
- X#else
- X strcpy(faxtype, "class2");
- X#endif
- X Faxtypes[0] = faxtype;
- X Faxtypes[1] = NULL;
- X wakeup[0] = '\0';
- X Wakeup[0] = wakeup;
- X Wakeup[1] = NULL;
- X Dialtyp[0] = 'T'; /* 'P' for pulse dialling */
- X Dialtyp[1] = '\0';
- X strcpy(dev, TEST_DEVICE);
- X Devices[0] = dev;
- X Devices[1] = NULL;
- X Devlocks[0] = wakeup; /* empty */
- X Devlocks[1] = NULL;
- X Topspeed[0] = '7'; /* 9600 baud, see modem docs */
- X Topspeed[1] = '\0';
- X#ifdef BLAH
- X blah = BLAH;
- X#endif
- X
- X sendfax((FILE *)NULL,0,TRUE);
- X exit(0);
- X}
- X#ifndef lint
- Xfax_log(va_alist)
- Xva_dcl
- X{
- X va_list args;
- X char *fmt;
- X int db_flag;
- X
- X va_start(args);
- X db_flag = va_arg(args, int);
- X fmt = va_arg(args, char *);
- X
- X if (db_flag == ERROR || (blah >= db_flag))
- X {
- X fprintf(stderr," ");
- X vfprintf(stderr, fmt, args);
- X }
- X va_end(args);
- X return(0);
- X}
- Xfax_tlog(va_alist)
- Xva_dcl
- X{
- X va_list args;
- X int db_flag;
- X FILE *fp;
- X char *fmt;
- X
- X va_start(args);
- X
- X db_flag = va_arg(args, int);
- X fp = va_arg(args, FILE *);
- X fmt = va_arg(args, char *);
- X
- X if (fp && (db_flag == ERROR || (blah >= db_flag)))
- X {
- X if (db_flag == ERROR)
- X fprintf(stderr,"%2d ",errno);
- X else fprintf(stderr," ");
- X vfprintf(stderr, fmt, args);
- X }
- X va_end(args);
- X return(0);
- X}
- Xfflushlog(){return(0);} /* don't bother with these while testing */
- Xnot_now(){return(0);} /* notnow() and rmjob() are in sendfax.c */
- Xrmjob(){return(0);} /* you don't want to link that in for tests */
- X
- X#endif /* lint */
- X#endif /* ******************* end of TESTING CODE ********************* */
- X
- X
- Xchar *faxtime(t) /* dont know how portable the ctime(3) variants are */
- Xtime_t t; /* in any case, all I need is the time */
- X{
- X static char permastore[40];
- X struct tm *tml, *localtime();
- X
- X tml = localtime(&t);
- X sprintf(permastore,"%02d:%02d:%02d",
- X tml->tm_hour,tml->tm_min,tml->tm_sec);
- X return(permastore);
- X}
- Xvoid breakwrite()
- X{
- X cannot = 1;
- X}
- Xportunlock(name)
- Xchar *name;
- X{
- X if (name)
- X unlink(name);
- X return(ERROR);
- X}
- X
- Xplug(portname,portlock)
- Xchar *portname, *portlock;
- X{
- X int i;
- X
- X errno = 0;
- X /* lock, allow possible incoming fax, or uucp, wait 5 mins */
- X /* if no luck, simply go away */
- X#ifndef TESTING
- X if (portlock)
- X if (mklock(portlock, 30, 300))
- X return(ERROR);
- X#endif
- X if ((ser_port = open(portname, (O_RDWR | O_NDELAY), 0600)) < 0)
- X {
- X if (errno == EBUSY)
- X fax_tlog(0, logfp, "sendfax: port %s BUSY\n",portname);
- X else fax_tlog(ERROR, logfp, "sendfax: can't plug into %s\n",portname);
- X return(portunlock(portlock));
- X }
- X if (ioctl(ser_port,TCGETS,&virgin) < 0)
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't ioctl on %s\n",portname);
- X return(portunlock(portlock));
- X }
- X wire = virgin; /* working copy */
- X
- X wire.c_iflag &= ~BRKINT; /* c_iflag is set to 0L, but looks */
- X wire.c_iflag &= ~ICRNL; /* cleaner when setting flags off */
- X wire.c_iflag &= ~ISTRIP;
- X wire.c_iflag &= ~IXON; /* can't use proper xon/xoff, see set_ixon() */
- X
- X wire.c_cflag &= ~CIBAUD;
- X wire.c_cflag &= ~B9600;
- X wire.c_cflag |= CSIZE;
- X wire.c_cflag |= CS8;
- X wire.c_cflag |= HUPCL;
- X wire.c_cflag |= CREAD;
- X wire.c_cflag |= B2400;
- X wire.c_cflag |= CSTOPB;
- X wire.c_cflag &= ~PARENB;
- X
- X wire.c_lflag &= ~ISIG;
- X/* wire.c_lflag &= ~ICANON; I now read this a line at a time */
- X wire.c_lflag &= ~ECHO;
- X wire.c_lflag &= ~IEXTEN;
- X
- X wire.c_oflag &= ~OPOST; /* no messing with output */
- X
- X wire.c_cc[VMIN] = 1;
- X wire.c_cc[VTIME] = 1;
- X wire.c_cc[VEOL] = 0x0d; /* need this to get the lines though */
- X /* or I would have to switch to ascii asnwers */
- X /* from the modem altogether - don't like it */
- X if (ioctl(ser_port,TCSETSF,&wire) < 0)
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't set 2400 baud for %s\n",portname);
- X return(portunlock(portlock));
- X }
- X
- X i = 1; /* probably SUN SPECIFIC, raise carrier */
- X if (ioctl(ser_port,TIOCSSOFTCAR, &i) < 0)
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't raise softcar on %s\n",portname);
- X return(portunlock(portlock));
- X }
- X if (fcntl(ser_port, F_SETFL, O_RDWR) == ERROR)
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't set O_NDELAY off for %s\n",portname);
- X return(portunlock(portlock));
- X }
- X fax_tlog(5, logfp, "sendfax: 2400 baud set for %s\n",portname);
- X return(0);
- X}
- Xfaxmode(portname,portlock)
- Xchar *portname,*portlock;
- X{
- X errno = 0;
- X /* pump up the volume to 19k2 */
- X wire.c_cflag &= ~B2400;
- X wire.c_cflag |= B19200;
- X
- X if (ioctl(ser_port,TCSETSW,&wire) < 0)
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't set 19200 baud for %s\n",portname);
- X return(portunlock(portlock));
- X }
- X fax_tlog(5, logfp, "sendfax: 19200 baud set for %s\n",portname);
- X return(0);
- X}
- Xset_ixon(on,portname,portlock)
- Xint on;
- Xchar *portname,*portlock;
- X{
- X/*
- X toggle flow control
- X there's no point trying to READ during transmit if
- X we're using CRTSCTS [hardware flow ctl], we
- X simply won't get anything even if the modem sends us some,
- X which in fact it does, namely xons and xoffs, even if we tell
- X the modem not to use xonoff flow ctl [tested on dos].
- X
- X I don't know if this is standard behaviour or if this
- X is a SunOs value added feature
- X
- X if you want to try your luck with xon/xoff, you have to set
- X flow ctl AFTER you've received your first XON [I know it's silly].
- X One problem you're likely to find is that the modem expects
- X the host to shut up instantly when sending an xoff.
- X
- X Testing on a dos box showed that by delaying the digesting of a
- X received xoff by two bytes screwed up the fax. It also showed
- X that the modem sends an xoff after fewer than 100
- X bytes were sent. At 19200 [~2000 bytes/sec] xon/xoff is thus toggled
- X more than 20 times a second. I guess this is just too much for unix
- X device drivers that are not guaranteed to stop instantly.
- X I could not get it to work on a 3/60 using xon/xoff reliably.
- X I'm too tired to even try it again on a 4/60. I use hardware
- X flow ctl. basta.
- X
- X feb 21st, '91: did not try xonoff again with icanon change
- X*/
- X errno = 0;
- X
- X if (on)
- X {
- X#ifdef USE_IXON
- X wire.c_iflag |= IXON;
- X#else
- X wire.c_cflag |= CRTSCTS;
- X#endif
- X }
- X else
- X {
- X#ifdef USE_IXON
- X wire.c_iflag &= ~IXON;
- X#else
- X wire.c_cflag &= ~CRTSCTS;
- X#endif
- X }
- X
- X if (ioctl(ser_port,TCSETSW,&wire) < 0)
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't %s flow ctl for %s\n",
- X (on)?"set":"unset",portname);
- X return(portunlock(portlock));
- X }
- X fax_tlog(9, logfp, "sendfax: flow_ctl %s for %s\n",
- X (on)?"set":"unset",portname);
- X return(0);
- X}
- Xunplug(portname,portlock)
- Xchar *portname,*portlock;
- X{
- X int i;
- X
- X wire.c_cflag = B0;
- X errno = 0;
- X
- X fax_tlog(5, logfp, "sendfax: hanging up on %s\n",portname);
- X if (ioctl(ser_port,TCSETS,&wire) < 0)
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't hang up %s\n",portname);
- X return(portunlock(portlock));
- X }
- X
- X i = 0; /* software carrier OFF */
- X if (ioctl(ser_port,TIOCSSOFTCAR, &i) < 0)
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't set softcar off for %s\n",portname);
- X return(portunlock(portlock));
- X }
- X close(ser_port);
- X
- X if (Wakeup[dev_no] && *(Wakeup[dev_no]))
- X resuscitate(portname);
- X
- X (void)portunlock(portlock);
- X return(0);
- X}
- Xresuscitate(dv) /* re enable auto answer */
- Xchar *dv;
- X{
- X int i;
- X
- X if (!plug(dv, NULL))
- X {
- X sprintf(txbuf,"%s\r\n",Wakeup[dev_no]);
- X write(ser_port, txbuf, strlen(txbuf));
- X sleep(1);
- X
- X i = 0;
- X if (ioctl(ser_port,TIOCSSOFTCAR, &i) < 0)
- X fax_tlog(ERROR, logfp, "sendfax: can't set softcar off for %s\n",dv);
- X close(ser_port);
- X }
- X}
- X
- Xsendfax(wfp, slot, canexit)
- XFILE *wfp;
- Xint slot, canexit;
- X{
- X int i;
- X char buf[256];
- X
- X dev_no = slot;
- X sent = failed = 0;
- X
- X sprintf(buf, "%s/FAX.LOG.%d", FAXLIB, getpid());
- X if ((logfp = fopen(buf, "w")) == NULL)
- X {
- X chmod(buf, FAXFMODE);
- X fax_log(ERROR, "sendfax: can't create temp log, I've had it\n");
- X if (canexit)
- X exit(1);
- X return;
- X }
- X for (i=0; i<MAX_MODEM; i++)
- X if (!strcmp(Faxtypes[slot], known_modems[i]))
- X break;
- X switch(i)
- X {
- X#ifdef CLASS2
- X case Class2: classyfax(); break;
- X#endif
- X#ifdef SIERRA
- X case Sierra: sierrafax(); break;
- X#endif
- X default:
- X fax_log(ERROR, "sendfax: unknown faxtype %s\n",Faxtypes[slot]);
- X }
- X if (wfp)
- X {
- X if (sent || failed)
- X xupdate(wfp); /* update or unlink x.fax file */
- X else fclose(wfp); /* no action, simply close file */
- X }
- X
- X fclose(logfp);
- X fflushlog(buf);
- X unlink(buf); /* get rid of tmp log */
- X if (canexit)
- X exit(0); /* else return */
- X}
- Xxupdate(fp)
- XFILE *fp;
- X{
- X int i;
- X struct tm *tml, *localtime();
- X
- X if (sent == fax.phone_nos)
- X {
- X fclose(fp);
- X#ifndef JOBID
- X fax_tlog(0, logfp, "sendfax: job %s, %d fax%s, completed\n",
- X fax.xname,fax.phone_nos,
- X (fax.phone_nos>1)?"es":"");
- X#else
- X fax_tlog(0, logfp, "sendfax: %s, jobid %s, %d fax%s, completed\n",
- X fax.xname,fax.jobid,fax.phone_nos,
- X (fax.phone_nos>1)?"es":"");
- X#endif
- X rmjob(fax.xname,fax.dname,fax.pages);
- X if (fax.mail)
- X {
- X tml = localtime(&fax.spooled);
- X ++tml->tm_mon; /* jan is 0 */
- X#ifndef JOBID
- X sprintf(wbuf,"echo 'your fax job %s, spooled %02d.%02d.%2d, %02d:%02d,\nhas been completed SUCCESSFUL' | mail %s",
- X fax.xname,
- X tml->tm_mday,tml->tm_mon,tml->tm_year,
- X tml->tm_hour,tml->tm_min,
- X fax.user);
- X#else
- X sprintf(wbuf,"echo 'your fax job %s, spooled %02d.%02d.%2d, %02d:%02d,\nhas been completed SUCCESSFUL' | mail %s",
- X fax.jobid,
- X tml->tm_mday,tml->tm_mon,tml->tm_year,
- X tml->tm_hour,tml->tm_min,
- X fax.user);
- X#endif
- X system(wbuf);
- X }
- X return;
- X }
- X else if (sent + foul == fax.phone_nos)
- X { /* created new jobs, unlink old one */
- X rmjob(fax.xname,fax.dname,fax.pages);
- X return;
- X }
- X
- X if (fseek(fp, fax.tpos, 0)) /* increment no of attempts */
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't update %s after sending %d fax%s\n",
- X fax.xname, sent, (sent>1)?"es":"");
- X return;
- X }
- X fprintf(fp, "tries %3d\n",1+fax.tries);
- X if (fseek(fp, fax.ppos, 0)) /* write out remaining phone nos */
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't update %s after sending %d fax%s\n",
- X fax.xname, sent, (sent>1)?"es":"");
- X return;
- X }
- X for (i=0; i<fax.phone_nos; i++)
- X if (fax.phone[i] != NULL)
- X fprintf(fp, "phone %s\n",fax.phone[i]);
- X fprintf(fp,"data %s\npages %d\n",fax.dname,fax.pages);
- X#ifdef JOBID
- X fprintf(fp,"jobid %s\n",fax.jobid);
- X#endif
- X fflush(fp);
- X if (ferror(fp))
- X fax_tlog(ERROR, logfp, "sendfax: can't update %s after sending %d fax%s\n",
- X fax.xname, sent, (sent>1)?"es":"");
- X fclose(fp);
- X}
- Xfork_off()
- X{
- X FILE *nj;
- X int i;
- X char dname[256];
- X
- X/*
- X remove foul jobs from batch on first attempt, so we don't
- X spoil a batch job because of one recipient whose fax gizzmo
- X is brain dead, switched off, run out of paper or so...
- X*/
- X
- X sprintf(wbuf, "%s/d.fb%05d%d",FAXSPOOL,getpid(),foul);
- X strcpy(dname, wbuf);
- X
- X for (i=0; i<fax.pages; i++)
- X {
- X sprintf(namebuf, "%s.g3.%d", fax.dname, i);
- X sprintf(biff, "%s.g3.%d", wbuf, i);
- X if (link(namebuf, biff))
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't link %s to %s for %s, x.file %s\n",
- X namebuf, biff, fax.phone[curjob],fax.xname);
- X return(ERROR);
- X }
- X }
- X sprintf(wbuf, "%s/x.fb%05d%d",FAXSPOOL,getpid(),foul);
- X
- X if ((nj = fopen(wbuf, "w")) == NULL)
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't create new x.file for %s, x.file %s\n",
- X fax.phone[curjob],fax.xname);
- X return(ERROR);
- X }
- X fprintf(nj,"spooled %ld\n",fax.spooled);
- X fprintf(nj,"tries %3d\n",1);
- X fprintf(nj,"user %s\n",fax.user);
- X fprintf(nj,"uid %d\n",fax.uid);
- X fprintf(nj,"now %d\n",fax.now);
- X fprintf(nj,"mail %d\n",fax.mail);
- X fprintf(nj,"type %d\n",fax.type);
- X fprintf(nj,"hires %d\n",fax.hires);
- X fprintf(nj,"font unknown\n"); /* that's done already */
- X fprintf(nj,"retfax unknown\n"); /* that's done as well */
- X fprintf(nj,"phone %s\n",fax.phone[curjob]);
- X fprintf(nj,"data %s\n",dname);
- X fprintf(nj,"pages %d\n",fax.pages);
- X#ifdef JOBID
- X fprintf(nj,"jobid %s\n",fax.jobid);
- X#endif
- X fflush(nj);
- X if (ferror(nj))
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't write to new x.file for %s, x.file %s\n",
- X fax.phone[curjob],fax.xname);
- X return(ERROR);
- X }
- X fclose(nj);
- X ++foul;
- X return(0);
- X}
- X
- X#ifdef SIERRA
- X
- Xlastframe(s, n)
- Xunsigned char *s;
- Xint n;
- X{
- X int i;
- X
- X if ((n -= 5) < 0)
- X return(ERROR);
- X for (i=0; i<n; i++)
- X if (*s++ == MARKER && (*s == 0xff) && (*(s+1) == 0xc8))
- X return(i);
- X return(ERROR);
- X}
- Xstrnpos(s, c, f, n) /* similar to strchr, but works on binary'\0'strings */
- Xunsigned char *s, c; /* ignores first 'f' bytes, len is in 'n' */
- Xint f, n; /* strings are likely to contain zero bytes */
- X{
- X int i;
- X
- X s += f;
- X for (i=f; i<n; i++)
- X if (*s++ == c)
- X return(i);
- X return(ERROR);
- X}
- Xstrnrpos(s, c, f, n) /* find last occurence of c in binary string of len n */
- Xunsigned char *s, c;
- Xint f, n;
- X{
- X int i, last;
- X
- X last = ERROR;
- X s += f;
- X for (i=f; i<n; i++) /* I don't like counting backwards */
- X if (*s++ == c)
- X last = i;
- X return(last);
- X}
- Xsierrafax()
- X{
- X int c, i, confirms, len, joberr, porterr, resend_cnt, tot_resends, alive;
- X FILE *fp;
- X time_t time_connect, time_hangup, *time_pstart, *time_pend;
- X
- X curjob = porterr = 0;
- X
- X sprintf(devnam,"%s",Devices[dev_no]);
- X sprintf(lcknam,"%s/%s",UUCPLOCKS,Devlocks[dev_no]);
- X
- X signal(SIGALRM, breakwrite);
- X siginterrupt(SIGALRM, 1); /* not sure if this is avail in Sys V */
- X signal(SIGHUP, breakwrite);
- X siginterrupt(SIGHUP, 1);
- X
- X while ((!porterr) && fax.phone[curjob] != NULL)
- X {
- X if (!fax.pages) /* just in case something breaks */
- X continue; /* cleanup will take care of it */
- X
- X if (not_now(fax.uid, fax.now, fax.phone[curjob]))
- X {
- X fax_tlog(5, logfp, "sendfax: bad time for %s\n",
- X fax.phone[curjob]);
- X ++curjob;
- X continue;
- X }
- X
- X#ifdef TESTING
- X fprintf(stderr, "\nsendfax: STARTUP\n");
- X#endif
- X i = line_minlen = have_cfr = have_connect =
- X have_dis = cannot = dial_tries = joberr = confirms =
- X tot_resends = resend_cnt = 0;
- X alive = TRUE;
- X
- X if (((time_pstart = (time_t *)calloc(fax.pages, sizeof(time_t))) == NULL)
- X || ((time_pend = (time_t *)calloc(fax.pages, sizeof(time_t))) == NULL))
- X return(fax_tlog(ERROR, logfp, "sendfax: can't allocate memory\n"));
- X
- X if (plug(devnam,lcknam))
- X return; /* errs logged already */
- X
- X /* force sync with modem */
- X /* sometimes it talks gibberish */
- X strcpy(wbuf, "ATE0V0\r\n");
- X do
- X {
- X if (to_modem(wbuf))
- X break;
- X if ((c = modem_c_ans(OK,8)) == 0 && i)
- X break;
- X } while (i++ < 5);
- X if (c || cannot)
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't sync with modem\n");
- X return(unplug(devnam, lcknam));
- X }
- X
- X sprintf(wbuf, "ATX4M%d#A0#B%c#E1#P%d#R%d#K%d#F1\r\n",
- X SPEAKER, Topspeed[dev_no], fax.pages, fax.hires, FLOW_CTL);
- X
- X if (to_modem(wbuf) || modem_c_ans(OK,8))
- X {
- X fax_tlog(ERROR, logfp, "sendfax: %s missing after #F1\n",
- X sierra_cmds[OK].txtstring);
- X return(unplug(devnam, lcknam));
- X }
- X
- X if (faxmode(devnam,lcknam)) /* errlogging done already */
- X return(unplug(devnam, lcknam));
- X sleep(2);
- X
- X sprintf(wbuf, "ATD%c%s\r\n",Dialtyp[dev_no], fax.phone[curjob]);
- X if (to_modem(wbuf))
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't dial\n");
- X return(unplug(devnam, lcknam));
- X }
- X/*
- X I don't know if 3*strlen(phone_no) is enough of a delay. Although tone
- X dialling the us is often instant [like nyc], some places in the uk
- X don't benefit from tone dial speed [yet]. When dialling germany I can
- X make some coffee, and get a news paper before I hear ok [or busy]
- X
- X Also note that "BUSY" is not recognised as such outside the US
- X*/
- X if ((c = modem_c_ans(ANSWER_TONE, 15+(3*strlen(fax.phone[curjob])) ))
- X == sierra_cmds[OK].retcode)
- X {
- X c = modem_c_ans(ANSWER_TONE,15+(3*strlen(fax.phone[curjob])));
- X /* it's possible the modem sends OK after receiving phone no */
- X }
- X
- X if (c == sierra_cmds[BUSY].retcode)
- X {
- X fax_tlog(5, logfp, "sendfax: %s BUSY\n",fax.phone[curjob]);
- X unplug(devnam,lcknam);
- X fflush(logfp);
- X sleep(5);
- X ++curjob;
- X continue;
- X }
- X else if (c)
- X {
- X /* could be non USA BUSY */
- X /* NEED TO WATCH THIS */
- X
- X for (i=0; i<LAST_SIERRA_ANS; i++)
- X if (c == sierra_cmds[i].retcode)
- X break;
- X fax_tlog(3, logfp, "sendfax: can't connect, have %s instead of ANSWER TONE for %s\n",
- X sierra_cmds[i].txtstring,fax.phone[curjob]);
- X unplug(devnam,lcknam);
- X fflush(logfp);
- X sleep(5);
- X ++curjob;
- X ++failed;
- X continue;
- X }
- X time_connect = time((time_t *)NULL);
- X
- X if (get_frame()) /* read hldc frame */
- X {
- X fax_tlog(ERROR, logfp, "sendfax: not a legal hldc frame on %s\n",
- X fax.phone[curjob]);
- X unplug(devnam,lcknam);
- X fflush(logfp);
- X
- X if ((!fax.tries) && (fax.phone_nos > 1))
- X {
- X if (!fork_off())
- X {
- X free(fax.phone[curjob]);
- X fax.phone[curjob] = NULL;
- X }
- X else break; /* something's seriously wrong */
- X } /* give up to avoid desaster */
- X sleep(5);
- X ++curjob;
- X ++failed;
- X continue;
- X }
- X
- X if (get_remote_cap()) /* read remote capabilities */
- X { /* might include identification [ignored] */
- X fax_tlog(ERROR, logfp, "sendfax: can't get remote capabilities on %s\n",
- X fax.phone[curjob]);
- X unplug(devnam,lcknam);
- X fflush(logfp);
- X
- X if ((!fax.tries) && (fax.phone_nos > 1))
- X {
- X if (!fork_off())
- X {
- X free(fax.phone[curjob]);
- X fax.phone[curjob] = NULL;
- X }
- X else break; /* something's seriously wrong */
- X } /* give up to avoid desaster */
- X sleep(5);
- X ++curjob;
- X ++failed;
- X continue;
- X }
- X
- X if (get_connect())
- X {
- X fax_tlog(ERROR, logfp, "sendfax: can't get CONNECT on %s\n",
- X fax.phone[curjob]);
- X unplug(devnam,lcknam);
- X sleep(5);
- X ++curjob;
- X ++failed;
- X continue;
- X }
- X set_minlen(have_connect);
- X
- X for (curpage=0; curpage<fax.pages;curpage++)
- X {
- X time_pstart[curpage] = time((time_t *)NULL);
- X sprintf(biff,"%s.g3.%d",fax.dname,curpage);
- X if ((fp = fopen(biff, "r")) == NULL)
- X {
- X unplug(devnam, lcknam);
- X fax_tlog(ERROR, logfp, "sendfax: can't open %s for %s\n",
- X biff, fax.phone[curjob]);
- X return; /* we're buggered somehow */
- X }
- X
- X#ifndef USE_IXON; /* else when using ixon/xoff, read XON before setting flow ctl */
- X if (set_ixon(TRUE,devnam,lcknam))
- X {
- X porterr = joberr = ERROR;
- X break;
- X }
- X#endif
- X
- X /* max tx time per full a4 page at 9k6 is < 60 secs */
- X /* alarm settings are based on 60 secs * 1.5, seems ok */
- X if (have_connect == CONNECT_24)
- X alarm(360);
- X else if (have_connect == CONNECT_48)
- X alarm(180);
- X else if (have_connect == CONNECT_72)
- X alarm(135);
- X else alarm(90);
- X
- X#ifdef USE_IXON /* you're out of luck on a sun, don't know about others */
- X fax_tlog(9, logfp, "sendfax: waiting for initial XON\n");
- X rxbuf[0] = '\0';
- X for (;;)
- X {
- X if (read(ser_port, rxbuf, 1) == 1)
- X if (rxbuf[0] == XON_CHAR)
- X break;
- X }
- X fax_tlog(9, logfp, "sendfax: GOT THAT\n");
- X /* have ixon, use flow ctl now */
- X if (set_ixon(TRUE,devnam,lcknam))
- X {
- X porterr = ERROR;
- X break;
- X }
- X
- X for (i=0; i<MAX_FAX_LINES; i++)
- X {
- X if ((len = getline(fp,txbuf,line_minlen)) == EOF)
- X break;
- X for (c=0; c<len; c++)
- X if (write(ser_port, &txbuf[c], 1) != 1)
- X {
- X porterr = joberr = ERROR;
- X fax_tlog(ERROR, logfp, "sendfax: can't write %d bytes to %s in page %d\n",
- X len,devnam,curpage);
- X break;
- X }
- X if (porterr)
- X break;
- X }
- X#else /* !USE_IXON, far less wear 'n tear, use it if you can */
- X for (i=0; i<MAX_FAX_LINES; i++)
- X {
- X if ((len = getline(fp,txbuf,line_minlen)) == EOF)
- X break;
- X if (write(ser_port, txbuf, len) != len)
- X {
- X sleep(2); /* force modem to time out, 1/10 sec is enough */
- X porterr = joberr = ERROR;
- X fax_tlog(ERROR, logfp, "sendfax: can't write %d bytes to %s in page %d\n",
- X len,devnam,curpage);
- X break;
- X }
- X }
- X#endif /* use_ixon */
- X alarm(0);
- X fclose(fp);
- X fax_tlog(9, logfp, "sendfax: %d scanlines sent\n",i);
- X
- X if (set_ixon(FALSE,devnam,lcknam))
- X {
- X porterr = ERROR; /*errs logged already */
- X break;
- X }
- X
- X if (!porterr)
- X c = modem_str_ans(MSG_CONFMD, 20, TRUE);
- X else c = porterr;
- X
- X time_pend[curpage] = time((time_t *)NULL);
- X if (c == sierra_cmds[RETRAIN].retcode)
- X {
- X --curpage;
- X ++tot_resends;
- X if (++resend_cnt == MAX_RESEND)
- X {
- X joberr = TRUE;
- X fax_tlog(ERROR, logfp, "sendfax: TOO MANY RESENDS, I've had it\n");
- X break;
- X }
- X }
- X else if (c == sierra_cmds[NO_CARRIER].retcode)
- X {
- X fax_tlog(ERROR, logfp, "sendfax: NO CARRIER after page %d of %d\n",
- X 1+curpage, fax.pages);
- X joberr = TRUE;
- X alive = FALSE;
- X break;
- X }
- X else if (c != sierra_cmds[MSG_CONFMD].retcode
- X && c != sierra_cmds[RTRN_OK].retcode)
- X {
- X for (i=0; i<LAST_SIERRA_ANS; i++)
- X if (c == sierra_cmds[i].retcode)
- X break;
- X fax_tlog(ERROR, logfp, "sendfax: unexpected response %s after page %d of %d\n",
- X sierra_cmds[i].txtstring,curpage+1,fax.pages);
- X joberr = TRUE;
- X alive = FALSE;
- X break;
- X }
- X else
- X {
- X fax_tlog(5, logfp, "sendfax: page %d of %d confirmed\n",
- X curpage+1,fax.pages);
- X confirms++;
- X resend_cnt = 0;
- X }
- X }
- X
- X/*
- X if we're still online, allow faxmodem to diconnect gracefully
- X at the other end, otherwise some fax machines remain in an
- X error condition barring further use. You're not gaining
- X popularity by jamming other people's fax toys
- X*/
- X if (alive)
- X (void)modem_str_ans(NO_CARRIER, 20, TRUE);
- X time_hangup = time((time_t *)NULL);
- X
- X unplug(devnam,lcknam);
- X
- X fax_tlog(0, logfp,
- X "sendfax: fax to %s, connect at %s\n",
- X fax.phone[curjob],faxtime(time_connect));
- X for (i=0; i<fax.pages; i++)
- X {
- X if ((!time_pstart[i]) || (!time_pend[i]))
- X break;
- X /* *faxtime() is static, stash away first use */
- X sprintf(biff,"%s, %ld secs\n",
- X faxtime(time_pend[i]),
- X (time_pend[i]-time_pstart[i]));
- X fax_tlog(0, logfp,
- X "sendfax: fax to %s, page %d, %s to %s",
- X fax.phone[curjob], i+1,
- X faxtime(time_pstart[i]),biff);
- X }
- X if (!tot_resends)
- X fax_tlog(0, logfp,
- X "sendfax: %s%s, connect time %ld secs\n",
- X (confirms==fax.pages)?"SUCCESSFUL: ":"",
- X fax.phone[curjob],
- X (time_hangup-time_connect));
- X else fax_tlog(0, logfp,
- X "sendfax: %s%s, %d RESENDS, connect time %ld secs\n",
- X (confirms==fax.pages)?"SUCCESSFUL: ":"",
- X fax.phone[curjob],
- X tot_resends,
- X (time_hangup-time_connect));
- X
- X if (joberr)
- X {
- X ++failed;
- X if ((!fax.tries) && (fax.phone_nos > 1))
- X {
- X if (!fork_off())
- X {
- X free(fax.phone[curjob]);
- X fax.phone[curjob] = NULL;
- X }
- X else break;
- X }
- X }
- X else
- X {
- X ++sent;
- X free(fax.phone[curjob]);
- X fax.phone[curjob] = NULL;
- X }
- X
- X free(time_pstart);
- X free(time_pend);
- X ++curjob;
- X fflush(logfp);
- X sleep(5); /* let the dust settle */
- X }
- X}
- Xmodem_c_ans(want,secs)
- Xint want, secs;
- X{
- X int nread, rlen;
- X static int fst;
- X char fred[4];
- X
- X fax_tlog(9, logfp, "sendfax: %swant %s, secs %d, attempt %d\n",
- X FUNCTION("modem_c_ans, "),sierra_cmds[want].txtstring,secs,fst);
- X
- X rxbuf[0] = '\0';
- X errno = nread = rlen = 0;
- X alarm(secs);
- X nread = read(ser_port, rxbuf, 6);
- X alarm(0);
- X
- X nread = max(nread,0); /* don't set rxbuf[-1] to '\0' on error */
- X rxbuf[nread] = '\0';
- X if (asclen(rxbuf) == 0 && (fst++ < 3))
- X return(modem_c_ans(want,secs));
- X fst = 0;
- X
- X /* since this is ascii directly from the modem it's quite safe */
- X if (strchr(rxbuf, sierra_cmds[want].retcode) == NULL)
- X {
- X if (blah == 9)
- X {
- X sprintf(biff, "sendfax: NOPE {%d bytes} ",nread);
- X for (rlen=0; rlen<nread; rlen++)
- X {
- X sprintf(fred,"%02x",rxbuf[rlen]);
- X strcat(biff, fred);
- X }
- X strcat(biff, "\n");
- X fax_tlog(9, logfp, biff);
- X }
- X return((rxbuf[0]) ? rxbuf[0] : ERROR);
- X }
- X fax_tlog(9, logfp, "sendfax: GOT THAT\n",errno);
- X return(0);
- X}
- Xmodem_str_ans(want,secs,newlot)
- Xint want, secs, newlot;
- X{
- X int nread, i, have, redo, left_marker, rite_marker;
- X static int fst;
- X char fred[4];
- X
- X errno = nread = 0;
- X if (newlot)
- X fst = 0;
- X for (i=0; i<128; i++)
- X rxbuf[i] = '\0';
- X
- X fax_tlog(9, logfp, "sendfax: %swant %s, secs %d, attempt %d\n",
- X FUNCTION("modem_str_ans, "),sierra_cmds[want].txtstring,secs,fst);
- X alarm(secs);
- X nread = read(ser_port, rxbuf, 128);
- X alarm(0);
- X
- X nread = max(nread,0);
- X rxbuf[nread] = '\0';
- X
- X have = left_marker = rite_marker = ERROR;
- X if (nread)
- X { /* do we have in rxbuf what we want ? */
- X if (rxbuf[0] == sierra_cmds[want].retcode)
- X have = TRUE;
- X /* check it's outside frame data markers */
- X left_marker = strnpos(rxbuf, MARKER, 0, nread);
- X rite_marker = strnrpos(rxbuf, MARKER, max(0,left_marker), nread);
- X }
- X
- X if (blah == 9)
- X {
- X sprintf(biff, "sendfax: read {%d bytes} ",nread);
- X for (i=0; i<nread; i++)
- X {
- X if (i == left_marker)
- X strcat(biff, "{");
- X sprintf(fred,"%02x",rxbuf[i]);
- X strcat(biff, fred);
- X if (i == rite_marker)
- X strcat(biff, "}");
- X if (i && (!(i % 32)))
- X strcat(biff, "\n");
- X }
- X strcat(biff, "\n");
- X fax_tlog(9, logfp, biff);
- X }
- X /* not found, or within frame data */
- X if (have == ERROR)
- X {
- X if (nread)
- X {
- X if (rxbuf[0] == sierra_cmds[NO_CARRIER].retcode)
- X return(sierra_cmds[NO_CARRIER].retcode);
- X
- X redo = FALSE;
- X if (rxbuf[0] == sierra_cmds[RETRAIN].retcode)
- X {
- X redo = sierra_cmds[RETRAIN].retcode;
- X fax_tlog(5, logfp, "sendfax: REQUEST to RESEND page %d of %d\n",
- X 1+curpage, fax.pages);
- X }
- X else if (rxbuf[0] == sierra_cmds[RTRN_OK].retcode)
- X {
- X fax_tlog(5, logfp, "sendfax: retrained successful after page %d of %d\n",
- X 1+curpage, fax.pages);
- X
- X if (1+curpage == fax.pages)
- X return(sierra_cmds[want].retcode);
- X redo = sierra_cmds[RTRN_OK].retcode;
- X }
- X
- X if (redo)
- X {
- X dial_tries = 0;
- X have_cfr = have_connect = 0;
- X if ((i = get_connect()) == 0)
- X return(redo);
- X return(i);
- X }
- X }
- X if (++fst >= 8)
- X return(ERROR);
- X return(modem_str_ans(want,secs,0));
- X }
- X fax_tlog(9, logfp, "sendfax: GOT THAT\n",errno);
- X fst = 0;
- X return(sierra_cmds[want].retcode);
- X}
- Xget_frame()
- X{
- X int i, nread, Nread, framestart, left_marker, rite_marker;
- X unsigned char timebyte;
- X char fred[4];
- X
- X /*
- X here's some typical "hdlc frames" as received from two
- X fax machines, including the training and retraining session
- X
- X nread = 121
- X 0d0a7effc004000088005182080404040404040404040404040404040400e800
- X 00748d7effc800721d0071247effffff7e0d0a620d0d0a7effc82157be7effff
- X fc7e0d0a670d7a0d0d0a7effc83275ec7efffffe7e0d0a680d0d0a7effc83275
- X ec7efffffe7e0d0a680d0d0a7effc82157be7efffffc7e0d0a
- X
- X nread = 166
- X 0d0a7effc00400008c00731d00e9b0bb0000bbbb0000bbbbbbbbbb8980600068
- X 6224b7c6b7a5b07effc0020404040404040404040404040404040404040404a4
- X f37effc80100731d0046147e7e7fff7e0d0a6b0d202020202020202020202020
- X 20202020202020200d0a620d0d0a7effc82157be7e7e787e0d0a670d7a0d0d0a
- X 7effc831458f7e7e7c7e0d0a6d0d0d0a7effc831458f7e7e7c7e0d0a6d0d330d
- X 8d0acf4b8d0a
- X
- X Frames vary in length. What we're looking for is the first substring
- X containing 7e ff c8. if we're not answering quick enough,
- X the two gizzmos seem to exchange/repeat some garbage
- X that we don't need to concern ourselves with. These frames are
- X rather large because I sat in a loop making the connection time
- X out on purpose. Expect to see 50 to 120 bytes in real life, though.
- X
- X I know of one make/model fax machine that does NOT send
- X "legal" hldc frames. I haven't found a way round this yet.
- X Ignoring it and assuming worts case seems not to help since
- X you don't get CFR and CONNECT [in a format that looks ok] either.
- X
- X This is such a bad frame:
- X 0d0a7e7effc00400008a00000981572e4d617965722042617520476d6248ffff
- X ffffffffffffffffffffffffff8260ffff0000ea727effc00200000000000000
- X 00000000000000000000000000000000000000000000000000008bef77ef7e0d
- X 0a6b0d0d0a7e7effc00400008a00000981572e4d617965722042617520476d62
- X 48ffffffffffffffffffffffffffffffff8260ffff0000ea727effc002000000
- X 00000000000000000000000000000000000000000000000000008bfeefde8bef
- X 77ef7e0d
- X
- X */
- X
- X for (i=0; i<256; i++) /* I've seen frames THAT long */
- X rxbuf[i] = '\0'; /* I know there's bcopy, memset etc */
- X /* can't be bothered now to ifdef portable */
- X Nread = errno = 0;
- X fax_tlog(9, logfp, "sendfax: want frame\n");
- X
- X alarm(45); /* just in case */
- X for (framestart=ERROR; Nread < 512;) /* and again */
- X {
- X if ((nread = read(ser_port, &rxbuf[Nread], 256)) > 0)
- X {
- X Nread += nread;
- X if ((framestart = lastframe(rxbuf, Nread)) >= 0
- X && framestart <= (Nread-6))
- X break;
- X }
- X if (cannot) /* alarm went off */
- X break;
- X }
- X alarm(0);
- X
- X left_marker = strnpos(rxbuf, MARKER, 0, Nread);
- X rite_marker = strnrpos(rxbuf, MARKER, left_marker, Nread);
- X
- X if (blah == 9)
- X {
- X fax_tlog(9, logfp, "sendfax: framelen %d, start of last frame %d\n",
- X Nread,framestart);
- X strcpy(biff,"sendfax: frame data\n");
- X for (i=0; i<Nread; i++)
- X {
- X if (i == left_marker && framestart > -1)
- X strcat(biff, "{");
- X else if (i == (framestart + 6) && framestart > -1)
- X strcat(biff, "->");
- X sprintf(fred, "%02x",rxbuf[i]);
- X strcat(biff, fred);
- X if (i == rite_marker && framestart > -1)
- X strcat(biff, "}");
- X if (i && (!(i % 32)))
- X strcat(biff, "\n");
- X }
- X strcat(biff, "\n");
- X fax_tlog(9, logfp, biff);
- X }
- X if (framestart == ERROR || cannot) /* cannot triggered by alarm */
- X return(ERROR); /* framestart == ERROR if no MARKER */
- X
- X timebyte = rxbuf[framestart+6];
- X timebyte = (timebyte >> 1) & 0x07; /* only want leftmost 3 bits in rite nibble */
- X line_minlen = not_so_fast[timebyte];
- X
- X fax_tlog(9, logfp, "sendfax: min usecs per line %d\n",line_minlen);
- X return(0);
- X}
- Xget_remote_cap()
- X{
- X int i, nread;
- X char fred[8];
- X
- X for (i=0; i<48; i++)
- X rxbuf[i] = '\0';
- X
- X nread = errno = 0;
- X fax_tlog(9, logfp, "sendfax: want REMOTE CAPABILITIES\n");
- X
- X alarm(30); /* just in case */
- X
- X for (;;)
- X {
- X if ((nread = read(ser_port, rxbuf, 48)) <= 0)
- X return(ERROR);
- X
- X if (blah == 9)
- X {
- X sprintf(biff, "sendfax: read {%d bytes} ",nread);
- X for (i=0; i<nread; i++)
- X {
- X sprintf(fred, "%02x",rxbuf[i]);
- X strcat(biff, fred);
- X }
- X strcat(biff, "\n");
- X fax_tlog(9, logfp, biff);
- X }
- X
- X if (nread >= 1 && rxbuf[0] == sierra_cmds[NO_CARRIER].retcode)
- X return(sierra_cmds[NO_CARRIER].retcode);
- X else if (nread == 2
- X && rxbuf[0] == sierra_cmds[WHAT_I_CAN].retcode)
- X {
- X have_dis = TRUE;
- X break;
- X }
- X }
- X if (cannot)
- X return(ERROR);
- X alarm(0);
- X fax_tlog(9, logfp, "sendfax: have REMOTE CAPABILITIES\n");
- X return(0);
- X}
- Xget_connect()
- X{
- X int nread, i, left_marker, rite_marker;
- X char fred[4];
- X
- X errno = 0;
- X rxbuf[0] = '\0';
- X if (blah == 9)
- X {
- X if (!have_cfr)
- X sprintf(biff,"sendfax: %swant %s, CONNECT, attempt %d\n",
- X FUNCTION("get_connect, "),sierra_cmds[CONFIRM_TO_RX].txtstring, dial_tries);
- X else sprintf(biff,"sendfax: %swant CONNECT, attempt %d\n",
- X FUNCTION("get_connect, "),dial_tries);
- X fax_tlog(9, logfp, biff);
- X }
- X
- X ++dial_tries;
- X alarm(25);
- X nread = read(ser_port, rxbuf, 256);
- X alarm(0);
- X
- X left_marker = strnpos(rxbuf, MARKER, 0, nread);
- X rite_marker = strnrpos(rxbuf, MARKER, max(0,left_marker), nread);
- X
- X if (blah == 9)
- X {
- X sprintf(biff, "sendfax: read {%d bytes} ",nread);
- X for (i=0; i<nread; i++)
- X {
- X if (i == left_marker)
- X strcat(biff, "{");
- X sprintf(fred,"%02x",rxbuf[i]);
- X strcat(biff, fred);
- X if (i == rite_marker)
- X strcat(biff, "}");
- X if (i && (!(i % 32)))
- X strcat(biff, "\n");
- X }
- X strcat(biff, "\n");
- X fax_tlog(9, logfp, biff);
- X }
- X
- X if (nread <= 0)
- X return(ERROR);
- X rxbuf[nread] = '\0';
- X
- X if ((!have_cfr) && rxbuf[0] == sierra_cmds[CONFIRM_TO_RX].retcode)
- X {
- X have_cfr = TRUE;
- X fax_tlog(9, logfp, "sendfax: have %s\n",sierra_cmds[CONFIRM_TO_RX].txtstring);
- X return(get_connect());
- X }
- X else if (rxbuf[0] == sierra_cmds[CRC_IN_FRAME].retcode)
- X {
- X fax_tlog(9, logfp, "sendfax: have %s\n",sierra_cmds[CRC_IN_FRAME].txtstring);
- X return(sierra_cmds[CRC_IN_FRAME].retcode);
- X }
- X else if (rxbuf[0] == sierra_cmds[NO_CARRIER].retcode)
- X {
- X fax_tlog(9, logfp, "sendfax: have %s\n",sierra_cmds[NO_CARRIER].txtstring);
- X return(sierra_cmds[NO_CARRIER].retcode);
- X }
- X else for (i=CONNECT_MIN; i<CONNECT_MAX; i++)
- X {
- X if (rxbuf[0] == sierra_cmds[i].retcode && have_cfr)
- X {
- X have_connect = sierra_cmds[i].retcode;
- X fax_tlog(9, logfp, "sendfax: have %s\n",sierra_cmds[i].txtstring);
- X return(0);
- X }
- X }
- X
- X if (dial_tries < 10) /* none found */
- X {
- X if (rxbuf[0] == sierra_cmds[RETRAIN].retcode)
- X --dial_tries;
- X return(get_connect());
- X }
- X return(ERROR); /* pointless, give up */
- X}
- Xset_minlen(c)
- Xint c;
- X{
- X double bits;
- X int i, j;
- X
- X /* line_minlen contains minimum microsecs per line */
- X /* assume worst case, 2400 baud, we're sending 2.4 bits/usec */
- X bits = 2.4;
- X
- X /* at higher speed we're sending more: */
- X for (i=CONNECT_MIN, j=1; i<CONNECT_MAX; i++, j++)
- X if (c == sierra_cmds[i].retcode)
- X {
- X bits *= (double)j;
- X break;
- X }
- X
- X#ifdef TESTING
- X if (i == CONNECT_MAX)
- X {
- X /* not really necessary, never seen anything strange */
- X fax_tlog(ERROR, logfp, "sendfax: Ooops - funny connect type %d\n",c);
- X line_minlen = 80; /* use a rubber */
- X }
- X else
- X#endif
- X {
- X bits *= (double)line_minlen;
- X line_minlen = (int)(bits/8.0) + (((int)(bits)%8)!=0);
- X /* line_minlen NOW contains min bytes per line */
- X }
- X fax_tlog(5, logfp, "sendfax: min bytes per line %d\n",line_minlen);
- X}
- Xgetline(fp,faxbuf,minlen)
- XFILE *fp;
- Xunsigned char *faxbuf;
- Xint minlen;
- X{
- X int i, c, idx, eol;
- X static int fst;
- X
- X if (eof)
- X {
- X eof = fst = FALSE;
- X return (EOF);
- X }
- X if (!fst++)
- X last1 = cur = 0xff;
- X
- X for (eol=idx=0; !eol;)
- X {
- X if ((c = getc(fp)) == EOF) /* add eop by hand */
- X {
- X eof = TRUE;
- X return(add_eop(faxbuf, minlen, idx));
- X }
- X last1 = cur;
- X cur = c;
- X
- X if ((!last1) && cur == 0x01)
- X eol = TRUE;
- X else if (eols)
- X {
- X if (((!last1) && cur == 0x10) || (last1 == 0x10 && cur == 0x01))
- X eol = TRUE;
- X }
- X
- X if (eol)
- X {
- X if (++eols == 6)
- X eof = TRUE;
- X else if (eols == 1)
- X {
- X faxbuf[idx++] = '\0';
- X faxbuf[idx++] = '\0';
- X faxbuf[idx++] = '\0';
- X if ((i = (minlen - idx)) > 0)
- X {
- X memcpy(&faxbuf[idx], zeros, i);
- X idx += i;
- X }
- X }
- X }
- X else if (cur)
- X eols = 0;
- X
- X faxbuf[idx++] = faxbyte[cur];
- X if (idx >= 1900)
- X {
- X fax_tlog(ERROR, logfp, "sendfax: don't think this is a fax file, scanline > %d pels\n",idx);
- X return(EOF);
- X }
- X }
- X return(idx);
- X}
- Xadd_eop(faxbuf, minlen, idx)
- Xunsigned char *faxbuf;
- Xint minlen, idx;
- X{
- X int x;
- X
- X fax_tlog(ERROR, logfp, "sendfax: strange fax file without EOP\n");
- X
- X faxbuf[idx++] = '\0';
- X faxbuf[idx++] = '\0';
- X faxbuf[idx++] = '\0';
- X if ((x = (minlen - idx)) > 0)
- X {
- X memcpy(&faxbuf[idx], zeros, x);
- X idx += x;
- X }
- X memcpy(&faxbuf[idx], eol_pat, sizeof(eol_pat));
- X return(idx+sizeof(eol_pat));
- X}
- X#endif
- X
- Xto_modem(s)
- Xchar *s;
- X{
- X int len, written;
- X
- X fax_tlog(9, logfp, "sendfax: sending %s",s); /* string contains \r\n */
- X len = strlen(s);
- X alarm(4);
- X written = write(ser_port, s, len);
- X alarm(0);
- X if (cannot || len != written)
- X return(ERROR);
- X sleep(1);
- X return(0);
- X}
- Xasclen(s)
- Xunsigned char *s;
- X{
- X unsigned char *d;
- X int i=0;
- X
- X d = s;
- X while (*s)
- X {
- X if (*s > ' ')
- X {
- X ++i;
- X *d++ = *s;
- X }
- X ++s;
- X }
- X *d = '\0';
- X return(i);
- X}
- END_OF_FILE
- if test 41916 -ne `wc -c <'faxhost/wiring.c'`; then
- echo shar: \"'faxhost/wiring.c'\" unpacked with wrong size!
- fi
- # end of 'faxhost/wiring.c'
- fi
- echo shar: End of archive 1 \(of 5\).
- cp /dev/null ark1isdone
- 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...
-