Path: toyokawa.gcd.bekkoame.or.jp!sengoku
From: sengoku@gcd.bekkoame.or.jp (Hiroaki Sengoku)
Newsgroups: fj.sources
Subject: CNG tone detector: FAX Modem Auto Answer Patch for mgetty-0.20
Date: 15 Apr 1995 14:06:48 +0900
Organization: Personal Site GCD, Yokohama JAPAN
Lines: 578
Distribution: fj
Message-ID: <3mnk98$umi@toyokawa.gcd.bekkoame.or.jp>
NNTP-Posting-Host: toyokawa.gcd.bekkoame.or.jp

$B@g@P!w2#IM;T$G$9!#(B

  Voice $B5!G=$,$D$$$F$$$J$$(B FAX modem $B$G!"(B

	      FAX/modem $B<+F0Ce?.(B & $BN1<iHVEEOC$H2s@~$r6&M-(B

  $B$9$k$?$a$N%Q%C%A$G$9!#(Bmgetty-0.20 $BMQ$G$9!#B?$/$N(B unix $B8_49(B OS $B$GMxMQ2D(B
$BG=$G$7$g$&!#;d$O(B Linux $B>e$G;H$C$F$$$^$9!#(B

$BMQ0U$9$k$b$N(B
************
		(1) FAX modem
		(2) sound card
		(3) $B%@%$%l%/%H%F%l%[%s%T%C%/%"%C%W(B
		(4) mgetty-0.20

  (1) $B$O(B FAX $B5!G=IU$G$J$/$F$b9=$$$^$;$s$,!"$=$N>l9g$OEvA3(B FAX $B$N<+F0Ce?.(B
$B$O=PMh$^$;$s(B :-)$B!#(B(2) $B$N(B sound card $B$O!"(Bunix $B8_49(B OS $B$G(B support $B$5$l$F$$(B
$B$l$P$J$s$G$b(B OK $B$G$9!#$3$N%Q%C%A$G$O(B /dev/dsp $B$r;H$C$F2;@<%G!<%?$rFI$_9~(B
$B$s$G$$$^$9!#$^$?!"(Bmixer $B$N@_Dj$r0l;~E*$KJQ99$7$^$9!#(B(3) $B$K4X$7$F$O2<$K=R(B
$B$Y$?!VCm0U!W$r$*FI$_2<$5$$!#(B(4) $B$O(B version $B$,(B 0.20 $B0J30$G$b!"MF0W$K%Q%C(B
$B%A$r$"$F$k$3$H$,2DG=$G$7$g$&!#(B

$B5!G=(B
****
  $BEEOC$,$+$+$C$F$-$F!"N1<iHVEEOC(B ($B$"$k$$$O?M4V(B) $B$,EEOC$K1~Ez$7$F$$$k$H$-!"(B
FAX $B$N(B CNG tone $B$,J9$3$($F$-$?$j!"(Bmodem $B$N(B CNG tone $B$,J9$3$($F$/$k$H!"(B
FAX modem $B$,2s@~$r6/@)E*$KC%$$!"(BFAX $B$"$k$$$O(B modem $B$N<+F0Ce?.$r9T$J$$$^(B
$B$9!#(B

$B%P%0(B
****
  CNG tone (1100Hz or 1300Hz) $B$K;w$?$h$&$J@<$r=P$9?M$+$iEEOC$,$+$+$C$F$-(B
$B$?;~$O8mF0:n$7$^$9!#(B:-) $B9b$$@<$r=P$9M'?M$,$$$k>l9g$OCm0U$7$^$7$g$&!#(B

mgetty $B$H$O(B ?
*************
  mgetty $B$OB?$/$N(B unix $B8_49(B OS $B$GF0:n$9$k(B FAX $B<u?.5!G=IU(B (uu)getty $B$G!"(B
Gert Doering <gert@greenie.muc.de> $B;a$K$h$C$F3+H/$5$l$^$7$?!#(B

  mgetty $B$rMQ$$$k$H(B FAX $B$N<+F0<u?.$H(B modem $B$N<+F0Ce?.$,=PMh$^$9!#$5$i$K(B
$B$A$g$C$H%=!<%9$r$$$8$l$P(B ring back $B$H$$$&J}K!$GN1<iHVEEOC$H2s@~$r6&M-$9(B
$B$k$3$H$,2DG=$G$9!#(Bring back $B$H$O!"(B

  $BEEOC$r$+$1$k(B -> 2, 3 $BEYLD$i$9(B -> $B0lC6@Z$k(B -> 1 $BJ,0JFb$K$+$1D>$9(B

$B$H(B FAX modem $B$,1~Ez$9$k;E3]$1$G$9!#$b$A$m$sIaDL$KEEOC$r$+$1$?>l9g$ON1<i(B
$BHVEEOC(B ($B$"$k$$$ON1<i$G$J$$>l9g$O?M4V(B) $B$,=P$^$9!#K\%Q%C%A$N$*$^$1$H$7$F!"(B
ring back $B5!G=$b$D$1$F$"$j$^$9$N$G!"(B(2), (3) $B$r$*;}$A$G$J$$J}$b8fMxMQ2<(B
$B$5$$!#(B

ring back $B$N7gE@(B
****************
  ring back $B$N:GBg$N7gE@$O8@$&$^$G$b$J$/EEOC$r(B 2 $BEY$+$1$kI,MW$,$"$k!"$H(B
$B$$$&$3$H$G$9!#(B1 $B2s$a$N8F=P$OEEOCNA6b$O$+$+$j$^$;$s$+$i$*6b$OL5BL$K$O$J$i(B
$B$J$$$N$G$9$,!"$$$+$s$;$s$a$s$I$/$5$$!#(BFAX $B$rAw$C$F$/$l$k?M$K$$$A$$$A(B 
ring back $B$NJ}K!$r65$($F$"$2$J$1$l$P$$$1$^$;$s!#CN?M$+$i(B FAX $B$r<u$1$k>l(B
$B9g$OLLE]=-$$J}K!$r6/@)$9$k(B (^^;) $B$3$H$b2DG=$G$9$,!"(Bshop $B$K(B FAX $B$G8+@Q$j(B
$B$rAw$i$;$k;~$K(B ring back $B$r@bL@$9$k$N$O8=<BE*$G$O$"$j$^$;$s!#(B

# ring back $B$G$o$6$o$6(B FAX $B$rAw$C$F$/$l$?J}!"$*<j?t$*$+$1$7$^$7$?!#(B(_O_)

FAX/modem $B$NH=JLK!(B
******************
  $BEEOC@~$N2;@<$r(B sound card $B$N%^%$%/C<;R$KF~NO$7$F!"EEOC@~$r%b%K%?$7$^$9!#(B
$BEEOC$,LD$C$?8e$NEEOC@~$N2;@<$r%U!<%j%(JQ49$7!"$b$7(B 1100Hz $B$"$k$$$O(B 
1300Hz $BIU6a$K%T!<%/$,$"$l$P(B FAX $B$"$k$$$O(B modem $B$+$i$N(B CNG tone $B$H$_$J$7(B
$B$^$9!#(B

$BCm0U(B
****
  $BEEOC@~$K$OG'Dj$r<u$1$?AuCV$7$+@\B3$9$k$3$H$O=PMh$^$;$s!#$7$?$,$C$FEEOC(B
$B@~$N2;@<$r(B sound card $B$N%^%$%/C<;R$KF~NO$9$k$?$a$N%"%@%W%?(B (3) $B$r9XF~$9(B
$B$kI,MW$,$"$j$^$9!#;d$,;H$C$?$N$O!"(B

	$B%F%l%[%s%"%/%;%5%j!<(B NT-100
	$BEEOC2s@~$h$j2;@<$r<h$j=P$9(B
	$B%@%$%l%/%H%F%l%[%s%T%C%/(B	SKYNIE CO.

$B$J$I$H=q$+$l$F$$$k$b$N$G$9!#Dj2A(B 1650 $B1_$G$9!#9XF~2A3J$OK:$l$^$7$?!#$b$A(B
$B$m$sF1EyIJ$J$i$J$s$G$b9=$$$^$;$s$,!"EE5$DL?.C<Kv5!4oG'DjHV9f$,$D$$$F$$$k(B
$B$+$I$&$+3NG'$7$F2<$5$$!#(B

$B$*$^$1(B
******
  $B@N$N(B modem $B$O(B CNG tone (1300Hz) $B$r=P$9$3$H$,=PMh$^$;$s!#$=$N>l9g$O!"%H!<(B
$B%s%@%$%"%k$G!V(B0$B!W$N2;$r=P$7$F2<$5$$!#!V(B0$B!W(B($B$@$1$8$c$J$/$F!"(B2, 5, 8 $B$I$l(B
$B$G$b(B OK $B$G$9$,(B) $B$O(B 1300Hz $BIU6a$K%T!<%/$,$"$j$^$9$+$i!"Ce?.$5$;$k$3$H$,2D(B
$BG=$G$9!#(B

$B$*$^$1$=$N(B 2
************
  Makefile $B$G!"(B-DRINGBACK $B$NA0$N%3%a%s%H$r30$;$P!"(Bring back $B5!G=IU$-$K$J(B
$B$j$^$9!#$,!"(Bring back $B$O!"$?$^$?$^(B 1 $BJ,0JFb$K(B 2 $BEYEEOC$,$+$+$C$F$/$k$H!"(B
modem $B$,1~Ez$7$F$7$^$$$^$9$N$G!"(B(2) $B$H(B (3) $B$r;}$C$F$$$kJ}$O(B ring back $B5!(B
$BG=$O(B off $B$K$7$F$*$$$?J}$,NI$$$G$7$g$&!#(B

# ring back $B$N$?$a$K!"$$$-$J$j(B FAX modem $B$N2;$rJ9$+$5$l$F$S$C$/$j$7$?J}!"(B
# $B$4$a$s$J$5$$!#(B(_O_)

$B$*$^$1$=$N(B 3
************
  fax_sense.c $B$r(B -DDEBUG $B$G(B compile $B$9$k$H!"%U!<%j%(JQ498e$N%G!<%?$rI8=`(B
$B=PNO$KEG$-$^$9!#EEOC@~$N2;@<(B (tone dial $B$N2;$H$+!"(Bdial tone $B$H$+(B) $B$K$I$s(B
$B$J<~GH?t$N2;$,4^$^$l$F$$$k$+D4$Y$F$_$k$HLLGr$$$+$b$7$l$^$;$s!#(B

$B%a%b(B
****
  $B%@%$%l%/%H%F%l%[%s%T%C%/%"%C%W$r;H$($P!"EEOC$,8=:_;HMQCf$+H]$+$r%A%'%C(B
$B%/$9$k$3$H$b=PMh$^$9!#;d$OEEOCCf$K(B uucp $B$N(B polling $B$,;O$^$C$?$j$7$J$$$h(B
$B$&$K$9$k$?$a!"(Buucico $B$r(B cron $B$+$i<B9T$9$kA0$KEEOC@~$,L52;>uBV$K$"$k$+3N(B
$BG'$9$k%W%m%0%i%`$rAv$i$;$F$$$^$9!#Hs>o$K4JC1$J%W%m%0%i%`$G$9$,!"M_$7$$?M$C(B
$B$F$$$^$9(B ?

$B%Q%C%A(B
******
  $B$3$N%Q%C%A$O!"(Bhttp://www.yajima.kuis.kyoto-u.ac.jp/staffs/sengoku/ $B$K(B
$BCV$/M=Dj$G$9!#(B

diff -u mgetty.c.org mgetty.c
--- mgetty.c.org	Thu Apr 21 19:10:57 1994
+++ mgetty.c	Wed Apr 12 20:52:19 1995
@@ -26,7 +26,6 @@
 #include <sys/stat.h>
 #include <signal.h>
 #include <fcntl.h>
-
 #include "mgetty.h"
 #include "policy.h"
 #include "tio.h"
@@ -203,6 +202,10 @@
 
 	char * fax_server_file = NULL;		
 
+#ifdef RINGBACK
+	time_t ringback = 0;
+#endif
+
 #ifdef VOICE
 	int answer_mode;
 	voice_path_init();
@@ -593,9 +596,17 @@
 		    && (what_action != DIST_RING_VOICE)
 #endif
 		   ) break;
+#ifdef FAXSENSE
+		fax_sense_start();
+#endif
 		rings++;
+#ifdef RINGBACK
+		if( time(NULL) - ringback < 60 ) rings = rings_wanted;
+#endif
 	    }
-
+#ifdef FAXSENSE
+	    if( fax_sense_end() > 0 ) rings = rings_wanted;
+#endif
 	    /* timeout - the phone stopped ringing? (human picked up) */
 	    if ( rings < rings_wanted && what_action == A_TIMOUT )
 	    {
@@ -606,6 +617,9 @@
 		    exit(0);		/* let init restart mgetty */
 		}
 		lprintf( L_MESG, "phone stopped ringing" );
+#ifdef RINGBACK
+		ringback = time(NULL);
+#endif
 		goto waiting;
 	    }
 
diff -u do_chat.c.org do_chat.c
--- do_chat.c.org	Mon Apr 18 22:02:56 1994
+++ do_chat.c	Sun Apr  9 21:31:12 1995
@@ -91,7 +91,16 @@
 		    break;
 		}
 		
+#ifdef FAXSENSE
+		cnt = fax_sense_read(fd, &buffer[i], 1, chat_timeout_time);
+		if( cnt == -2 ) {
+		    errno = EINTR;
+		    retcode = FAIL;
+		    break;
+		}
+#else
 		cnt = read( fd, &buffer[i], 1 );
+#endif
 
 		if ( cnt < 0 )
 		{
diff -u fax_sense.c.org fax_sense.c
--- fax_sense.c.org	Fri Apr 14 20:49:43 1995
+++ fax_sense.c	Wed Apr 12 21:07:49 1995
@@ -0,0 +1,349 @@
+/*
+ * fax_sense.c	sense MIC to detect CNG tone
+ * Copyright(C)1995 by Hiroaki Sengoku <sengoku@gcd.bekkoame.or.jp>
+ * Version 1.0	Apr 8, 1995
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Emacs; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <ulimit.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/soundcard.h>
+#include <math.h>
+#ifdef DEBUG
+#include <stdarg.h>
+#define L_ERROR 1
+#define L_WARN 3
+#define L_MESG 4
+#else
+#include "mgetty.h"
+#endif
+#ifndef EINTR
+#include <errno.h>
+#endif
+
+#ifndef PI
+#define		PI			3.1415926535897932384626
+#endif
+#ifndef NSTAGE
+#define		NSTAGE		10
+#endif
+
+#define		NSAMPLE		(1<<NSTAGE)
+#define		CNG_FREQ	143		/* 1100 Hz */
+#define		VCNG_FREQ	169		/* 1300 Hz */
+#define		FREQ_WIDTH	5
+
+/* FFT */
+
+typedef struct {
+	double r;	/* real */
+	double i;	/* imaginary */
+} Complex;
+
+static Complex addc(Complex a, Complex b) {
+	Complex ret;
+	ret.r = a.r + b.r;
+	ret.i = a.i + b.i;
+	return ret;
+}
+
+static Complex mulc(Complex a, Complex b) {
+	Complex ret;
+	ret.r = a.r * b.r - a.i * b.i;
+	ret.i = a.r * b.i + a.i * b.r;
+	return ret;
+}
+
+static void mkSinTbl(int n, Complex *tbl) {	/* W=-2pi/n pitch sin => tbl */
+	int i;
+	for( i=0; i < n; i++ ) {
+		tbl[i].r = cos(2*PI*i/n);
+		tbl[i].i = -sin(2*PI*i/n);
+	}
+}
+
+static void mkRevTbl(int *tbl) {	/* bit reverse table => tbl */
+	int i, j, k;
+	for( i=0; i < NSAMPLE; i++ ) {
+		tbl[i] = 0;
+		for( j=0, k=i; j < NSTAGE; j++, k >>= 1 ) {
+			tbl[i] <<= 1;
+			tbl[i] |= (k & 1);
+		}
+	}
+}
+
+static Complex sinTbl[NSAMPLE];	/* sin table */
+
+static void butterfly(Complex *y, int stage, int node) {
+	int pair;		/* distance between pair nodes */
+	int p, p2;		/* power of W */
+	Complex t[2];
+	int i, j;
+	pair = 1 << stage;
+	p = (NSAMPLE/2)/pair;
+	for( i=0; i < 2; i++ ) {
+		t[i].r = t[i].i = 0;
+		p2 = (node+pair*i)*p;
+		for( j=0; j < 2; j++ ) {
+			t[i] = addc(t[i],mulc(sinTbl[p2*j % NSAMPLE],y[node + pair*j]));
+		}
+	}
+	for( i=0; i < 2; i++ ) y[node + pair*i] = t[i];
+}
+
+static void fft(Complex *y) {
+	int stage;		/* stage of butterflies */
+	int node;		/* node number */
+	int pair;		/* distance between pair nodes */
+	int size;		/* size of butterfly */
+	int i;
+	for( stage=0; stage < NSTAGE; stage++ ) {
+		pair = 1 << stage;
+		size = pair * 2;
+		for( node=0; node < NSAMPLE; node += size )
+			for( i=0; i < pair; i++ ) butterfly(y,stage,node+i);
+	}
+	for( i=0; i < NSAMPLE; i++ ) {
+		y[i].r /= NSAMPLE;
+		y[i].i /= NSAMPLE;
+	}
+}
+
+/* sense FAX */
+
+static int revTbl[NSAMPLE];		/* bit reverse table */
+
+#ifdef DEBUG
+static void lprintf(int level, const char *fmt, ...) {
+	char buf[256];
+	va_list args;
+	va_start(args, fmt);
+	vsprintf(buf,fmt,args);
+	va_end(args);
+	fprintf(stderr,"[%d] %s\n",level,buf);
+}
+#endif
+
+static int set_mixer(int baz, int foo, int bar) {
+	if( ioctl(baz,MIXER_WRITE(foo),&bar) == -1 ) {
+		lprintf(L_ERROR,"fail to set mixer");
+		return -1;
+	}
+	return 0;
+}
+
+static int get_mixer(int baz, int foo) {
+	int bar;
+	if( ioctl(baz,MIXER_READ(foo),&bar) == -1 ) {
+		lprintf(L_ERROR,"fail to get mixer setting");
+		return -1;
+	}
+	return bar & ((0x7f <<8) | 0x7f);
+}
+
+static float peak(float *a, int width, int *pos) {
+	float max, min;
+	int i, peak = 0;
+	max = 0;
+	for( i=-width; i < width; i++ ) if( a[i] > max ) max = a[peak=i];
+	max = 0;
+	for( i=peak-width/2; i < peak+width/2; i++ ) max += a[i];
+	min = 0;
+	for( i=peak-width; i < peak-width/2; i++ ) min += a[i];
+	for( i=peak+width/2; i < peak+width; i++ ) min += a[i];
+	*pos = peak;
+	if( max < 10 ) return 0;	/* ignore noise */
+	return max/min;
+}
+
+static int sense(unsigned char *x) {
+	Complex y[NSAMPLE];
+	float a[NSAMPLE/2];
+	float p_fax, p_modem;
+	int pos_fax, pos_modem;
+	char *msg;
+	int j, ret;
+	ret = 0;
+	for( j=0; j < NSAMPLE/2; j++ ) a[j] = 0;
+	for( j=0; j < NSAMPLE; j++ ) {
+		y[j].r = (float)(x[revTbl[j]]-128);
+		y[j].i = 0;
+	}
+	fft(y);
+#ifdef DEBUG
+	for( j=0; j < NSAMPLE/2; j++ )
+		a[j] += y[j].r * y[j].r + y[j].i * y[j].i;
+#else
+	for( j=CNG_FREQ-FREQ_WIDTH*2; j < CNG_FREQ+FREQ_WIDTH*2; j++ )
+		a[j] += y[j].r * y[j].r + y[j].i * y[j].i;
+	for( j=VCNG_FREQ-FREQ_WIDTH*2; j < VCNG_FREQ+FREQ_WIDTH*2; j++ )
+		a[j] += y[j].r * y[j].r + y[j].i * y[j].i;
+#endif
+	p_fax = peak(&a[CNG_FREQ],FREQ_WIDTH,&pos_fax);
+	p_modem = peak(&a[VCNG_FREQ],FREQ_WIDTH,&pos_modem);
+	if( p_fax > 10 ) {
+		ret = 1;
+		msg = " -> FAX !";
+	} else if( p_modem > 10 ) {
+		ret = 2;
+		msg = " -> MODEM !";
+	} else msg = "";
+	lprintf(ret ? L_WARN : L_MESG,"sense CNG: %.0f(%d), V.25: %.0f(%d)%s",
+			p_fax,pos_fax,p_modem,pos_modem,msg);
+#ifdef DEBUG
+	for( j=0; j < NSAMPLE/2; j++ ) printf("%9.6f\n",a[j]);
+#endif
+	return ret;
+}
+
+static int save_vol, save_mic, save_rec, save_recsrc;
+static int initialized = 0;
+static Complex X[NSAMPLE];
+static int fax_fd;
+static int fax_sense_ret = 0;
+
+int fax_sense_start() {	/* save volumes ... */
+	int recsrc, baz;
+	char *name;
+	if( initialized ) {		/* synchronize */
+		if( ioctl(fax_fd,SNDCTL_DSP_SYNC) == -1 ) {	/* now start sampling */
+			lprintf(L_ERROR,"fail to synchronize dsp");
+			return -1;
+		}
+		return 0;
+	}
+	name = "/dev/dsp";
+	if( (fax_fd=open(name,O_RDONLY)) < 0 ) {
+		lprintf(L_ERROR,"Can't open %s",name);
+		return -1;
+	}
+	name = "/dev/mixer";
+	if( (baz=open(name,O_RDWR)) < 0 ) {
+		lprintf(L_ERROR,"Can't open %s",name);
+		return -1;
+	}
+	save_vol = get_mixer(baz,SOUND_MIXER_VOLUME);
+	save_rec = get_mixer(baz,SOUND_MIXER_RECLEV);
+	save_mic = get_mixer(baz,SOUND_MIXER_MIC);
+	if( save_rec == -1
+	   || save_vol == -1
+	   || set_mixer(baz,SOUND_MIXER_VOLUME,  0) == -1			/* mute */
+	   || set_mixer(baz,SOUND_MIXER_RECLEV,(100<<8)|100) == -1	/* full */
+	   || set_mixer(baz,SOUND_MIXER_MIC,   (100<<8)|100) == -1
+	   ) return -1;
+	if( ioctl(baz, SOUND_MIXER_READ_RECSRC, &save_recsrc) == -1 ) {
+		lprintf(L_ERROR,"fail to read recsrc");
+		return -1;
+	}
+	recsrc = SOUND_MASK_MIC;	/* recording MIC only */
+	if( ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &recsrc) == -1 ) {
+		lprintf(L_ERROR,"fail to write recsrc");
+		return -1;
+	}
+	close(baz);
+	usleep(200000);		/* wait 0.2 sec */
+	mkSinTbl(NSAMPLE,sinTbl);
+	mkRevTbl(revTbl);
+	fax_sense_ret = 0;
+	initialized = 1;	/* successfuly initialized */
+	return fax_fd;
+}
+
+int fax_sense() {
+	unsigned char buf[NSAMPLE];
+	if( !initialized ) return 0;
+	if( read(fax_fd,buf,NSAMPLE) != NSAMPLE ) {
+		lprintf(L_ERROR,"read error: audio device");
+		return 0;
+	}
+	return sense(buf);
+}
+
+int fax_sense_end() {	/* restore volumes ... */
+	int baz;
+	char *name;
+	if( !initialized ) return 0;
+	name = "/dev/mixer";
+	if( (baz=open(name, O_RDWR)) < 0 ) {
+		lprintf(L_ERROR,"Can't open %s",name);
+		return -1;
+	}
+	if( ioctl(baz, SOUND_MIXER_WRITE_RECSRC, &save_recsrc) == -1 ) {
+		lprintf(L_ERROR,"fail to write recsrc");
+		return -1;
+	}
+	if(   set_mixer(baz,SOUND_MIXER_MIC,   save_mic) == -1
+	   || set_mixer(baz,SOUND_MIXER_RECLEV,save_rec) == -1 ) return -1;
+	usleep(200000);	/* wait 0.2 sec */
+	if(   set_mixer(baz,SOUND_MIXER_VOLUME,save_vol) == -1 ) return -1;
+	close(baz);
+	close(fax_fd);
+	initialized = 0;
+	return fax_sense_ret;
+}
+
+int fax_sense_read(int fd, char *buf, size_t size, time_t timeout) {
+    fd_set fds, rfds;
+	int width;
+	int ret;
+	time_t t;
+	struct timeval timezero;
+	if( !initialized ) return read(fd,buf,size);
+    FD_ZERO(&fds);
+	FD_SET(fd,&fds);
+	width = ulimit(4,0);
+	timezero.tv_sec = timezero.tv_usec = 0;
+	for( t=time(NULL); time(NULL)-t < timeout; ) {
+		rfds = fds;
+		if( select(width,&rfds,NULL,NULL,&timezero) < 0 ) break;
+		if( FD_ISSET(fd,&rfds) ) return read(fd,buf,size);
+		ret = fax_sense();
+		if( ret > 0 ) {
+			fax_sense_ret = ret;
+			return -2;
+		}
+	}
+	errno = EINTR;
+	return -1;
+}
+
+#ifdef DEBUG
+int main(int argc, char *argv[]) {
+	int ret;
+	char c;
+	do {
+		c = 0;
+		fax_sense_start();
+		fax_sense_read(0,&c,1,8);
+	} while( c == 0x0a );
+	ret = fax_sense_end();
+	if( ret == 1 ) fprintf(stderr,"FAX detected !\n");
+	else if( ret == 2 ) fprintf(stderr,"MODEM detected !\n");
+}
+#endif
+
+/*
+ * For Gnu Emacs.
+ * Local Variables:
+ * tab-width: 4
+ * End:
+ */
diff -u Makefile.org Makefile
--- Makefile.org	Mon Apr 25 08:22:44 1994
+++ Makefile	Sun Apr  9 20:10:29 1995
@@ -84,7 +84,7 @@
 #	    USTAT	  - ustat(), no statfs etc.
 #
 #CFLAGS=-Wall -g -O2 -pipe -DSECUREWARE -DUSE_POLL
-CFLAGS=-g -O2 -Wall -pipe
+CFLAGS=-g -O2 -Wall -pipe -DFAXSENSE #-DRINGBACK 
 #CFLAGS=-g -O -DSVR4
 #CFLAGS=-g -O -DSVR4 -DSVR42
 #CFLAGS=-g -O -DUSE_POLL
@@ -106,7 +106,7 @@
 #
 # For Sequent Dynix/ptx, you have to add "-lsocket"
 #
-LDFLAGS=
+LDFLAGS=-lm
 #LDFLAGS=-lprot -lsocket
 #LDFLAGS=-s -shlib
 #LDFLAGS=-lsocket
@@ -194,7 +194,8 @@
 #
 OBJS=mgetty.o logfile.o do_chat.o locks.o utmp.o logname.o login.o \
      faxrec.o faxsend.o faxlib.o faxhng.o \
-     io.o gettydefs.o tio.o config.o cnd.o getdisk.o
+     io.o gettydefs.o tio.o config.o cnd.o getdisk.o \
+     fax_sense.o
 
 SFAXOBJ=sendfax.o logfile.o locks.o faxlib.o faxsend.o faxrec.o \
      io.o tio.o faxhng.o cnd.o getdisk.o
--
					        $B@g@P(B $B9@L@(B @ $B2#IM;T@DMU6h(B
#303.					      sengoku@gcd.bekkoame.or.jp
<A HREF="http://www.yajima.kuis.kyoto-u.ac.jp/staffs/sengoku/">info.</A>
