Hylafax Mailing List Archives

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

Re: hylafax-v4.0pl1: deal correctly with "class 1.0" modem; send softResetCmd in faxgetty



Yesterday, I wrote:

>  Date: Wed, 30 Jul 1997 20:09:25 -0400
>  From: "Jonathan I. Kamens" <jik@kamens.brookline.ma.us>
>  
>  The patch below fixes two problems:
>  
>  1) My modem, a SupraExpress 56e, responds "0,1,1.0" to "at+fclass=?".
>  Unfortunately, hylafax was assuming that the only modem class with a
>  period in it is 2.0, which means that "1.0" gets incremented by the
>  parser to "2" and faxgetty thinks my modem supports class 2, which it
>  doesn't.  I added a SERVICE_CLASS10 constant, and added "Class 1.0" to
>  the modem class names, and that seemed to solve the problem.
>  
>  2) The documentation claims that the daemons send the soft reset
>  command to the modem, but I couldn't find any evidence that they do
>  so, either by reading and searching source code or by looking in the
>  server and session traces.  I modified faxd/ClassModem.c++ to send the
>  soft reset command before the other reset commands.

My patch was incorrect; it was treating "2.0" in the response to
"at+fclass=?" as SERVICE_CLASS10, which is clearly wrong.

Here's a new, somewhat more complex patch to replace the one I sent
yesterday.  It adds new functionality to the ClassModem::vparseRange
function to allow a two-dimensional "mapping array" to be specified;
I've explained the new functionality in a comment above vparseRange in
the diff.

--- util/class2.h	1997/07/30 16:39:44	1.1
+++ util/class2.h	1997/07/31 00:10:07
@@ -45,8 +45,9 @@
 // service types returned by +fclass=?
 const int SERVICE_DATA	 = BIT(0);	// data service
 const int SERVICE_CLASS1 = BIT(1);	// class 1 interface
-const int SERVICE_CLASS2 = BIT(2);	// class 2 interface
-const int SERVICE_CLASS20 = BIT(3);	// class 2.0 interface
+const int SERVICE_CLASS10 = BIT(2);	// class 1.0 interface
+const int SERVICE_CLASS2 = BIT(3);	// class 2 interface
+const int SERVICE_CLASS20 = BIT(4);	// class 2.0 interface
 const int SERVICE_VOICE	 = BIT(8);	// voice service (ZyXEL extension)
 const int SERVICE_ALL	 = BIT(9)-1;
 
--- faxd/Class2.c++	1997/07/31 14:56:25	1.1
+++ faxd/Class2.c++	1997/07/31 15:32:29
@@ -134,7 +134,7 @@
     int sep = 0;
     int pwd = 0;
     if (doQuery(conf.class2APQueryCmd, s))
-	(void) vparseRange(s, 3, &sub, &sep, &pwd);
+	(void) vparseRange(s, 0, 0, 3, &sub, &sep, &pwd);
     if (sub & BIT(1)) {
 	saCmd = conf.class2SACmd;
 	modemSupports("subaddressing");
@@ -501,7 +501,7 @@
 fxBool
 Class2Modem::parseRange(const char* cp, Class2Params& p)
 {
-    if (!vparseRange(cp, 8, &p.vr,&p.br,&p.wd,&p.ln,&p.df,&p.ec,&p.bf,&p.st))
+    if (!vparseRange(cp, 0, 0, 8, &p.vr,&p.br,&p.wd,&p.ln,&p.df,&p.ec,&p.bf,&p.st))
 	return (FALSE);
     p.vr &= VR_ALL;
     p.br &= BR_ALL;
--- faxd/ClassModem.c++	1997/07/16 10:57:20	1.1
+++ faxd/ClassModem.c++	1997/07/31 16:03:40
@@ -52,14 +52,27 @@
 const char* ClassModem::serviceNames[9] = {
     "\"Data\"",			// SERVICE_DATA
     "\"Class 1\"",		// SERVICE_CLASS1
+    "\"Class 1.0\"",		// SERVICE_CLASS10
     "\"Class 2\"",		// SERVICE_CLASS2
-    "\"Class 2.0\"",		// SERVICE_CLASS20 (XXX 3)
-    "",				// 4
+    "\"Class 2.0\"",		// SERVICE_CLASS20
     "",				// 5
     "",				// 6
     "",				// 7
     "\"Voice\"",		// SERVICE_VOICE
 };
+/*
+  Bits corresponding to various service classes.  The first column is
+  for when there is no ".0", the second colum for when there is.
+
+  If there end up being ".1", ".2", etc. classes later, this can be
+  extended by changing the number of columns in the array.
+*/
+#define MAX_SERVICE_CLASS 2
+static const int serviceBits[3][MAX_VPARSE_POINT+2] = {
+  {SERVICE_DATA, SERVICE_DATA},
+  {SERVICE_CLASS1, SERVICE_CLASS10},
+  {SERVICE_CLASS2, SERVICE_CLASS20},
+};
 const char* ClassModem::ATresponses[13] = {
     "Nothing",			// AT_NOTHING
     "OK",			// AT_OK
@@ -129,7 +142,8 @@
      */
     // XXX: workaround yet another GCC bug (sigh)
     const fxStr& flow = conf.getFlowCmd(conf.flowControl);
-    resetCmds = "AT"
+    resetCmds = conf.softResetCmd 
+	      | "\nAT"
 	      | stripAT(conf.resetCmds)		// prepend to insure our needs
 	      | stripAT(conf.echoOffCmd)
 	      | stripAT(conf.verboseResultsCmd)
@@ -981,19 +995,68 @@
 const char COMMA = ',';
 const char SPACE = ' ';
 
+static int
+parseInt(const char **in_ptr)
+{
+  const char *ptr = *in_ptr;
+  int val = 0;
+  
+  if (! isdigit(*ptr))
+    return -1;
+  
+  do {
+    val = 10*val+(*ptr - '0');
+  } while (isdigit(*++ptr));
+
+  *in_ptr = ptr;
+  return val;
+}
+
+static void
+addBit(const int major, const int point, const int max,
+       const int map_array[0][MAX_VPARSE_POINT+2], int * const mask)
+{
+  if (! max) {
+    if (major <= 31)
+      *mask |= 1<<major;
+  }
+  else if (major <= max && point <= MAX_VPARSE_POINT)
+    *mask |= map_array[major][point+1];
+}
+
 /*
- * Parse a Class 2 parameter range string.  This is very
- * forgiving because modem vendors do not exactly follow
- * the syntax specified in the "standard".  Try looking
- * at some of the responses given by rev ~4.04 of the
- * ZyXEL firmware (for example)!
+ * Parse a Class 2 parameter range string, possibly remapping bits
+ * with decimal numbers in them.  This is very forgiving because modem
+ * vendors do not exactly follow the syntax specified in the
+ * "standard".  Try looking at some of the responses given by rev
+ * ~4.04 of the ZyXEL firmware (for example)!
  *
  * NB: We accept alphanumeric items but don't return them
  *     in the parsed range so that modems like the ZyXEL 2864
  *     that indicate they support ``Class Z'' are handled.
+ * 
+ * When "max" is non-zero, then it should specify the height of the
+ * "map_array" array, which should contain in its slots the bits to
+ * set for each "a.b" pair.  Column 0 in the array represents what bit
+ * to assign when there is no decimal part of a number; column 1
+ * represents what bit to assign when the number of the decimal is
+ * "1", etc.  For example, this array:
+ * 
+ * { { BIT(0), BIT(1) },
+ *   { BIT(2), BIT(2) },
+ *   { BIT(3), BIT(4) } };
+ * 
+ * Will assign BIT(0) for the parameter "0", BIT(1) for "0.0", BIT(2)
+ * for either "1" or "1.0", BIT(3) for "2", and BIT(4) for "2.0".
+ * Bits whose decimal parts are larger than MAX_VPARSE_POINT or whose
+ * whole parts are larger than "max" are ignored.  When no "max" and
+ * "map_array" are specified, the decimal parts of parameters are
+ * ignored.
  */
 fxBool
-ClassModem::vparseRange(const char* cp, int nargs ... )
+ClassModem::vparseRange(const char* cp, const int max, 
+			const int map_array[][MAX_VPARSE_POINT+2], 
+			int nargs ... )
 {
     fxBool b = TRUE;
     va_list ap;
@@ -1024,38 +1087,56 @@
 		b = FALSE;
 		goto done;
 	    }
-	    int v;
+	    int v, vpoint;
 	    if (isdigit(cp[0])) {
-		v = 0;
-		do {
-		    v = v*10 + (cp[0] - '0');
-		} while (isdigit((++cp)[0]));
+		vpoint = -1;
+		if ((v = parseInt(&cp)) < 0) {
+		  b = FALSE;
+		  goto done;
+		}
 	    } else {
 		v = -1;					// XXX skip item below
 		while (isalnum((++cp)[0]))
 		    ;
 	    }
-	    int r = v;
+	    int r = -1, rpoint = -1;
+	    if (cp[0] == '.') {				// <d.b>
+		cp++;
+		if ((vpoint = parseInt(&cp)) < 0) {
+		  b = FALSE;
+		  goto done;
+		}
+	    }
 	    if (cp[0] == '-') {				// <low>-<high>
 		cp++;
 		if (!isdigit(cp[0])) {
 		    b = FALSE;
 		    goto done;
 		}
-		r = 0;
-		do {
-		    r = r*10 + (cp[0] - '0');
-		} while (isdigit((++cp)[0]));
-	    } else if (cp[0] == '.') {			// <d.b>
-		cp++;
-		while (isdigit(cp[0]))			// XXX
-		    cp++;
-		v++, r++;				// XXX 2.0 -> 3
+		if ((r = parseInt(&cp)) < 0) {
+		  b = FALSE;
+		  goto done;
+		}
+		rpoint = -1;
+		if (cp[0] == '.') {
+		  cp++;
+		  if ((rpoint = parseInt(&cp)) < 0) {
+		    b = FALSE;
+		    goto done;
+		  }
+		}
 	    }
 	    if (v != -1) {				// expand range or list
-		r = fxmin(r, 31);			// clamp to valid range
-		for (; v <= r; v++)
-		    mask |= 1<<v;
+	      if (r == -1) {
+		r = v;
+		rpoint = vpoint;
+	      }
+	      for (; v <= r; v++) {
+		int max_point = (v == r) ? rpoint : MAX_VPARSE_POINT;
+		for (; vpoint <= max_point; vpoint++)
+		  addBit(v, vpoint, max, map_array, &mask);
+		vpoint = -1;
+	      }
 	    }
 	    if (acceptList && cp[0] == COMMA)		// (<item>,<item>...)
 		cp++;
@@ -1078,7 +1159,7 @@
 fxBool
 ClassModem::parseRange(const char* cp, u_int& a0)
 {
-    return vparseRange(cp, 1, &a0);
+    return vparseRange(cp, MAX_SERVICE_CLASS, serviceBits, 1, &a0);
 }
 
 void



Home
Report any problems to webmaster@hylafax.org

HylaFAX is a trademark of Silicon Graphics Corporation.
Internet connectivity for hylafax.org is provided by:
VirtuALL Private Host Services