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