HylaFAX The world's most advanced open source fax server

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: [hylafax-users] receiving: logic of RTN negative followed by MPS



Giulio Orsero wrote:

On 4/26/06, Giulio Orsero <giulioo@xxxxxxxxx> wrote:

On 4/25/06, Lee Howard <faxguy@xxxxxxxxxxxxxxxx> wrote:
> Try the attached patch. It causes the DCN signal to be sent instead of
> RTN, and that should cause the sender to hang up or send DCN in reply,
> and the received but poor-quality page will get saved by virtue of
> SaveUnconfirmedPages... I hope.


The patch worked as intended.

So with this patch the sender knew something was wrong and could do
something about it, both sender and receiver happy.


Attached is a patch that I'm now committing to the repository at hylafax.sourceforge.net. It will be in the 4.3.0.3 subrelease there. It adds a feature called "BadPageHandlingMethod". I've included the man page documentation below.

To accomplish the setting you desired here you would do:

BadPageHandlingMethod: DCN

My recommended setting would generally be the default, which is:

BadPageHandlingMethod: RTN-SAVE

I've not made this work in Class 2 because I'm too lazy to do that part... the Class 2 code isn't as easy to manipulate here, it doesn't seem... since it may be difficult to control the modem's behavior as desired... especially when it performs copy-quality checking/correction.

Thanks,

Lee.

--------------------------------------------------
BadPageHandlingMethod

(Class 1/1.0 only) Specifies how to react to a bad page received from the remote sender: one of ‘‘RTN’’, ‘‘DCN’’, or ‘‘RTN-SAVE’’.

If a page is received in non-ECM mode with unacceptable quality according to PercentGoodLines or MaxConseutiveBadLines then it can be somewhat difficult to inform the sender of the problem. Historically, HylaFAX has assumed that signalling RTN to the sender will accomplish this. However, some senders are incapable of retransmitting pages, and to reduce burden they treat an RTN signal as a receipt confirmation and proceed to the next page without notifying the sending user of the potential problem in readability on the receive-end. (The assumption there being that the receiving user will notify the sending user if there actually is a redability problem.)

A setting of ‘‘RTN’’ is the historic behavior and assumes that an RTN signal will be enough to get the sender to retransmit or be otherwise informed of a potential readability problem on the receive-end. The previously-received page data is marked to be overwritten by the next page data received from the sender.

A setting of ‘‘DCN’’ tells HylaFAX to transmit a DCN signal in response to the post-page message and should trigger a call abortion by the sender. This should clearly indicate a problem in page readability to the sender, although the receipt of any following pages in a later call cannot be guaranteed.

A setting of ‘‘RTN-SAVE’’ more closely approximates the behavior of other fax receivers (especially fax machines). It causes HylaFAX to send the RTN signal but it saves the previously received page data and places the next transmitted page data in another page. This is the default setting. However, this could result in multiple copies of the same page image being saved in the same file - if the sender does indeed retransmit the unacceptable pages during the same call.

diff -Nru hylafax.orig/faxd/Class1.h hylafax/faxd/Class1.h
--- hylafax.orig/faxd/Class1.h	2006-05-02 15:54:08.000000000 -0700
+++ hylafax/faxd/Class1.h	2006-05-03 17:57:46.000000000 -0700
@@ -139,7 +139,7 @@
 		    u_int f3, const fxStr& nsf,
 		    u_int f4, const fxStr& id,
 		    u_int f5, FaxParams& dics,
-		    u_int timer, fxStr& emsg);
+		    u_int timer, bool notransmit, fxStr& emsg);
     bool	recvDCSFrames(HDLCFrame& frame);
     bool	recvTraining();
     bool	recvPPM(int& ppm, fxStr& emsg);
diff -Nru hylafax.orig/faxd/Class1Poll.c++ hylafax/faxd/Class1Poll.c++
--- hylafax.orig/faxd/Class1Poll.c++	2006-05-02 15:54:08.000000000 -0700
+++ hylafax/faxd/Class1Poll.c++	2006-05-03 18:04:19.000000000 -0700
@@ -66,5 +66,5 @@
 	    0, fxStr::null,
 	    FCF_CIG, cig,
 	    FCF_DTC, dtc,
-	    conf.t1Timer, emsg);
+	    conf.t1Timer, false, emsg);
 }
diff -Nru hylafax.orig/faxd/Class1Recv.c++ hylafax/faxd/Class1Recv.c++
--- hylafax.orig/faxd/Class1Recv.c++	2006-05-02 15:54:08.000000000 -0700
+++ hylafax/faxd/Class1Recv.c++	2006-05-04 15:41:04.521958792 -0700
@@ -107,7 +107,7 @@
 	FCF_NSF|FCF_RCVR, nsf,
 	FCF_CSI|FCF_RCVR, lid,
 	FCF_DIS|FCF_RCVR, dis,
-	conf.class1RecvIdentTimer, emsg);
+	conf.class1RecvIdentTimer, false, emsg);
 }
 
 /*
@@ -138,38 +138,40 @@
     u_int f3, const fxStr& nsf,
     u_int f4, const fxStr& id,
     u_int f5, FaxParams& dics,
-    u_int timer, fxStr& emsg)
+    u_int timer, bool notransmit, fxStr& emsg)
 {
     u_int t1 = howmany(timer, 1000);		// in seconds
     u_int trecovery = howmany(conf.class1TrainingRecovery, 1000);
     time_t start = Sys::now();
     HDLCFrame frame(conf.class1FrameOverhead);
-    bool framesSent;
+    bool framesSent = false;
 
     emsg = "No answer (T.30 T1 timeout)";
-    /*
-     * Transmit (PWD) (SUB) (CSI) DIS frames when the receiving
-     * station or (PWD) (SEP) (CIG) DTC when initiating a poll.
-     */
-    if (f1) {
-	startTimeout(7550);
-	framesSent = sendFrame(f1, pwd, false);
-	stopTimeout("sending PWD frame");
-    } else if (f2) {
-	startTimeout(7550);
-	framesSent = sendFrame(f2, addr, false);
-	stopTimeout("sending SUB/SEP frame");
-    } else if (f3) {
-	startTimeout(7550);
-	framesSent = sendFrame(f3, (const u_char*)HYLAFAX_NSF, nsf, false);
-	stopTimeout("sending NSF frame");
-    } else {
-	startTimeout(7550);
-	framesSent = sendFrame(f4, id, false);
-	stopTimeout("sending CSI/CIG frame");
+    if (!notransmit) {
+	/*
+	 * Transmit (PWD) (SUB) (CSI) DIS frames when the receiving
+	 * station or (PWD) (SEP) (CIG) DTC when initiating a poll.
+	 */
+	if (f1) {
+	    startTimeout(7550);
+	    framesSent = sendFrame(f1, pwd, false);
+	    stopTimeout("sending PWD frame");
+	} else if (f2) {
+	    startTimeout(7550);
+	    framesSent = sendFrame(f2, addr, false);
+	    stopTimeout("sending SUB/SEP frame");
+	} else if (f3) {
+	    startTimeout(7550);
+	    framesSent = sendFrame(f3, (const u_char*)HYLAFAX_NSF, nsf, false);
+	    stopTimeout("sending NSF frame");
+	} else {
+	    startTimeout(7550);
+	    framesSent = sendFrame(f4, id, false);
+	    stopTimeout("sending CSI/CIG frame");
+	}
     }
     for (;;) {
-	if (framesSent) {
+	if (framesSent && !notransmit) {
 	    if (f1) {
 		startTimeout(7550);
 		framesSent = sendFrame(f2, addr, false);
@@ -191,7 +193,7 @@
 		stopTimeout("sending DIS/DCS frame");
 	    }
 	}
-	if (framesSent) {
+	if (framesSent || notransmit) {
 	    /*
 	     * Wait for a response to be received.  We wait T2
 	     * rather than T4 due to empirical evidence for that need.
@@ -259,17 +261,19 @@
 	 * be in the process of sending training.
 	 */
 	pause(conf.class1TrainingRecovery);
-	/*
-	 * Retransmit ident frames.
-	 */
-	if (f1)
-	    framesSent = transmitFrame(f1, pwd, false);
-	else if (f2)
-	    framesSent = transmitFrame(f2, addr, false);
-	else if (f3)
-	    framesSent = transmitFrame(f3, (const u_char*)HYLAFAX_NSF, nsf, false);
-	else
-	    framesSent = transmitFrame(f4, id, false);
+	if (!notransmit) {
+	    /*
+	     * Retransmit ident frames.
+	     */
+	    if (f1)
+		framesSent = transmitFrame(f1, pwd, false);
+	    else if (f2)
+		framesSent = transmitFrame(f2, addr, false);
+	    else if (f3)
+		framesSent = transmitFrame(f3, (const u_char*)HYLAFAX_NSF, nsf, false);
+	    else
+		framesSent = transmitFrame(f4, id, false);
+	}
     }
     return (false);
 }
@@ -469,15 +473,27 @@
 bool
 Class1Modem::recvPage(TIFF* tif, u_int& ppm, fxStr& emsg, const fxStr& id)
 {
-    if (lastPPM == FCF_MPS && prevPage && pageGood) {
+    if (lastPPM == FCF_MPS && prevPage) {
 	/*
 	 * Resume sending HDLC frame (send data)
 	 * The carrier is already raised.  Thus we
 	 * use sendFrame() instead of transmitFrame().
 	 */
-	startTimeout(7550);
-	(void) sendFrame((sendERR ? FCF_ERR : FCF_MCF)|FCF_RCVR);
-	stopTimeout("sending HDLC frame");
+	if (pageGood) {
+	    startTimeout(7550);
+	    (void) sendFrame((sendERR ? FCF_ERR : FCF_MCF)|FCF_RCVR);
+	    stopTimeout("sending HDLC frame");
+	} else if (conf.badPageHandling == FaxModem::BADPAGE_RTNSAVE) {
+	    startTimeout(7550);
+	    (void) sendFrame(FCF_RTN|FCF_RCVR);
+	    stopTimeout("sending HDLC frame");
+	    FaxParams dis = modemDIS();
+	    if (!recvIdentification(0, fxStr::null, 0, fxStr::null, 
+		0, fxStr::null, 0, fxStr::null, 0, dis,
+		conf.class1RecvIdentTimer, true, emsg)) {
+		return (false);
+	    }
+	}
     }
 
     time_t t2end = 0;
@@ -697,13 +713,15 @@
 		    pageGood = false;
 		    if (params.ec != EC_DISABLE) return (false);
 		}
-		if (!pageGood) recvResetPage(tif);
+		if (!pageGood && conf.badPageHandling == FaxModem::BADPAGE_RTN)
+		    recvResetPage(tif);
 		if (signalRcvd == 0) tracePPM("RECV recv", lastPPM);
 
 		/*
 		 * [Re]transmit post page response.
 		 */
-		if (pageGood) {
+		if (pageGood || conf.badPageHandling == FaxModem::BADPAGE_RTNSAVE) {
+		    if (!pageGood) lastPPM = FCF_MPS;	// FaxModem::BADPAGE_RTNSAVE
 		    /*
 		     * If post page message confirms the page
 		     * that we just received, write it to disk.
@@ -801,7 +819,10 @@
 			    } else {
 				(void) transmitFrame((sendERR ? FCF_ERR : FCF_MCF)|FCF_RCVR);
 			    }
-			    tracePPR("RECV send", sendERR ? FCF_ERR : FCF_MCF);
+			    if (pageGood)
+				tracePPR("RECV send", sendERR ? FCF_ERR : FCF_MCF);
+			    else
+				tracePPR("RECV send", FCF_RTN);
 			}
 			/*
 			 * Reset state so that the next call looks
@@ -835,8 +856,9 @@
 			emsg = "Failure to receive silence.";
 			return (false);
 		    }
-		    (void) transmitFrame(FCF_RTN|FCF_RCVR);
-		    tracePPR("RECV send", FCF_RTN);
+		    u_int rtnfcf = conf.badPageHandling == FaxModem::BADPAGE_DCN ? FCF_DCN : FCF_RTN;
+		    (void) transmitFrame(rtnfcf|FCF_RCVR);
+		    tracePPR("RECV send", rtnfcf);
 		    /*
 		     * Reset the TIFF-related state so that subsequent
 		     * writes will overwrite the previous data.
diff -Nru hylafax.orig/faxd/FaxModem.h hylafax/faxd/FaxModem.h
--- hylafax.orig/faxd/FaxModem.h	2006-05-02 15:54:08.000000000 -0700
+++ hylafax/faxd/FaxModem.h	2006-05-02 17:07:25.000000000 -0700
@@ -44,6 +44,7 @@
 // NB: these would be enums in the FaxModem class
 //     if there were a portable way to refer to them!
 typedef unsigned int RTNHandling;       // RTN signal handling method 
+typedef unsigned int BadPageHandling;	// bad page (received) handling method 
 typedef unsigned int JBIGSupport;	// JBIG support available
 
 /*
@@ -176,6 +177,11 @@
         RTN_IGNORE     = 2,         // ignore error and send next page
         RTN_RETRANSMITIGNORE = 3    // retransmit but ignore error instead of hanging up
     };
+    enum {			// FaxModem::BadPageHandling
+	BADPAGE_RTN     = 0,	// send RTN, expect a retransmission
+	BADPAGE_DCN     = 1,	// send DCN, expect a disconnection
+	BADPAGE_RTNSAVE = 2	// send RTN, but save the page
+    };
     enum {			// FaxModem::JBIGSupport
 	JBIG_NONE = 0,		    // no JBIG support
 	JBIG_RECV = 1,		    // receive-only JBIG support
diff -Nru hylafax.orig/faxd/ModemConfig.c++ hylafax/faxd/ModemConfig.c++
--- hylafax.orig/faxd/ModemConfig.c++	2006-05-02 15:54:08.000000000 -0700
+++ hylafax/faxd/ModemConfig.c++	2006-05-02 17:03:06.000000000 -0700
@@ -265,6 +265,7 @@
     setVolumeCmds("ATM0 ATL0M1 ATL1M1 ATL2M1 ATL3M1");
     recvDataFormat	= DF_ALL;		// default to no transcoding
     rtnHandling         = FaxModem::RTN_RETRANSMITIGNORE; // retransmit until MCF/MPS
+    badPageHandling	= FaxModem::BADPAGE_RTNSAVE; // send RTN but save the page
     saveUnconfirmedPages = true;		// keep unconfirmed pages
     softRTFCC		= true;			// real-time fax comp. conv. (software)
     noAnswerVoice	= false;		// answer voice calls
@@ -575,6 +576,20 @@
 }
 
 u_int
+ModemConfig::getBadPageHandling(const char* cp)
+{
+    BadPageHandling bph;
+    if (valeq(cp, "RTN")) {
+	bph = FaxModem::BADPAGE_RTN;
+    } else if (valeq(cp, "DCN")) {
+	bph = FaxModem::BADPAGE_DCN;
+    } else {
+	bph = FaxModem::BADPAGE_RTNSAVE;
+    }
+    return (bph);
+}
+
+u_int
 ModemConfig::getJBIGSupport(const char* cp)
 {
     JBIGSupport js;
@@ -725,6 +740,8 @@
 	recvDataFormat = getDataFormat(value);
     else if (streq(tag, "rtnhandlingmethod"))
         rtnHandling = getRTNHandling(value);
+    else if (streq(tag, "badpagehandlingmethod"))
+        badPageHandling = getBadPageHandling(value);
     else if (streq(tag, "class2ecmtype"))
 	class2ECMType = getECMType(value);
     else if (streq(tag, "class2usehex"))
diff -Nru hylafax.orig/faxd/ModemConfig.h hylafax/faxd/ModemConfig.h
--- hylafax.orig/faxd/ModemConfig.h	2006-05-02 15:54:08.000000000 -0700
+++ hylafax/faxd/ModemConfig.h	2006-05-02 17:10:01.000000000 -0700
@@ -57,6 +57,7 @@
     u_int	getSpeed(const char* value);
     u_int	getDataFormat(const char* value);
     u_int       getRTNHandling(const char* cp);
+    u_int       getBadPageHandling(const char* cp);
     u_int       getJBIGSupport(const char* cp);
     ECMType	getECMType(const char* cp);
 
@@ -228,6 +229,7 @@
     u_int	recvDataFormat;		// received facsimile data format
 
     RTNHandling rtnHandling;            // RTN signal handling method
+    BadPageHandling badPageHandling;	// bad page (received) handling method
     JBIGSupport	class1JBIGSupport;	// monochrome JBIG support
     bool	saveUnconfirmedPages;	// don't delete unconfirmed pages
     
diff -Nru hylafax.orig/man/hylafax-config.4f hylafax/man/hylafax-config.4f
--- hylafax.orig/man/hylafax-config.4f	2006-05-02 15:54:08.000000000 -0700
+++ hylafax/man/hylafax-config.4f	2006-05-04 15:38:39.889946200 -0700
@@ -120,6 +120,7 @@
 AnswerRotary	string	\s-1Any\s+1	alternatives for answering calls
 AnswerBias	integer	\-	bias to apply to successful rotary answer 
 AreaCode\(S2	string	\-	local area code
+BadPageHandlingMethod	string	\s-1RTN-SAVE\s+1	bad page received handling method	
 BatchLogs\(S1	boolean	\s-1Yes\s+1	keep all session logs of a batch in a single log
 CallIDAnswerLength	integer	\-	answer call when CallIDPattern received
 CallIDPattern	strint	\-	call identification pattern string
@@ -507,6 +508,44 @@
 .B DialStringRules
 below.)
 .TP
+.B BadPageHandlingMethod
+(Class 1/1.0 only) Specifies how to react to a bad page received from the remote sender:
+one of ``\s-1RTN\s+1'', ``\s-1DCN\s+1'', or ``\s-1RTN-SAVE\s+1''.
+
+If a page is received in non-ECM mode with unacceptable quality 
+according to
+.BR PercentGoodLines
+or
+.BR MaxConseutiveBadLines
+then it can be somewhat difficult to inform the sender of the problem.
+Historically, \*(Fx has assumed that signalling RTN to the sender will
+accomplish this.  However, some senders are incapable of retransmitting
+pages, and to reduce burden they treat an RTN signal as a receipt 
+confirmation and proceed to the next page without notifying the sending
+user of the potential problem in readability on the receive-end.  (The
+assumption there being that the receiving user will notify the sending
+user if there actually is a redability problem.)
+
+A setting of ``\s-1RTN\s+1'' is the historic behavior and assumes that 
+an RTN signal will be enough to get the sender to retransmit or be
+otherwise informed of a potential readability problem on the receive-end.
+The previously-received page data is marked to be overwritten by the next page
+data received from the sender.
+
+A setting of ``\s-1DCN\s+1'' tells \*(Fx to transmit a DCN signal in 
+response to the post-page message and should trigger a call abortion by
+the sender.  This should clearly indicate a problem in page readability
+to the sender, although the receipt of any following pages in a later
+call cannot be guaranteed.
+
+A setting of ``\s-1RTN-SAVE\s+1'' more closely approximates the behavior
+of other fax receivers (especially fax machines).  It causes \*(Fx to
+send the RTN signal but it saves the previously received page data and places
+the next transmitted page data in another page.  This is the default
+setting.  However, this could result in multiple copies of the same page
+image being saved in the same file - if the sender does indeed retransmit
+the unacceptable pages during the same call.
+.TP
 .B BatchLogs\(S1
 When sending or recieving multiple documents (denoted by EOM), this
 value determines if the session logs span the entire batch or, if set



Project hosted by iFAX Solutions