faxd/Class2.c++
/*
 * Check if the modem is a Class 2 modem and, if so,
 * configure it for use.  We try to confine a lot of
 * the manufacturer-specific bogosity here and leave
 * the remainder of the Class 2 support fairly generic.
 */
Check if the modem is a Class 2 modem and, if so,
configure it for use.  We try to confine a lot of
the manufacturer-specific bogosity here and leave
the remainder of the Class 2 support fairly generic.
Check if the modem is a Class 2 modem and if so configure it for use . We try to confine a lot of the manufacturer - specific bogosity here and leave the remainder of the Class 2 support fairly generic .
bool
Class2Modem::setupModem(bool isSend)
{
    if (!selectBaudRate(conf.maxRate, conf.flowControl, conf.flowControl))
	return (false);
    fxStr s;
    if (doQuery(conf.classQueryCmd, s, 5000) && FaxModem::parseRange(s, modemServices))
	traceBits(modemServices & SERVICE_ALL, serviceNames);
    if ((modemServices & serviceType) == 0)
	return (false);
    atCmd(classCmd);
    if (setupManufacturer(modemMfr)) {
	modemCapability("Mfr " | modemMfr);
	modemMfr.raisecase();
    }
    (void) setupModel(modemModel);
    (void) setupRevision(modemRevision);
    if (modemModel != "")
	modemCapability("Model " | modemModel);
    if (modemRevision != "")
	modemCapability("Revision " | modemRevision);
    fxStr t30parms;
    if (!doQuery(dccQueryCmd, t30parms, 500)) {
	serverTrace("Error getting modem capabilities");
	return (false);
    }
    if (!parseRange(t30parms, modemParams)) {
	serverTrace("Error parsing " | dccQueryCmd | " response: "
	    "\"" | t30parms | "\"");
	return (false);
    }
    if (conf.class2ECMType == ClassModem::ECMTYPE_CLASS20 ||
       (conf.class2ECMType == ClassModem::ECMTYPE_UNSET && serviceType != SERVICE_CLASS2)) {
	    modemParams.ec ^= BIT(EC_DISABLE);	
	    modemParams.ec <<= 1;		
	    modemParams.ec |= BIT(EC_DISABLE);	
	    if (modemParams.ec & BIT(EC_ENABLE256))
		modemParams.ec |= BIT(EC_ENABLE64);
    }
    bool jbigsupported = false;
    switch (conf.class2JBIGSupport) {
	case FaxModem::JBIG_FULL:
	    jbigsupported = true;
	    break;
	case FaxModem::JBIG_SEND:
	    jbigsupported = isSend;
	    break;
	case FaxModem::JBIG_RECV:
	    jbigsupported = !isSend;
	    break;
	}
    if (!jbigsupported) {
	modemParams.df &= ~BIT(DF_JBIG);
    }
    traceModemParams();
    cqCmds = "";
    sendCQ = 0;
    if (serviceType == SERVICE_CLASS2) {
	if (doQuery(conf.class2CQQueryCmd, s) && FaxModem::parseRange(s, modemCQ)) {
	    if (modemCQ >>= 1)
		cqCmds = conf.class2CQCmd;
	} else
	    modemCQ = 0;
	static const char* whatCQ[4] = { "no", "1D", "2D", "1D+2D" };
	modemSupports("%s copy quality checking%s", whatCQ[modemCQ&3],
	    (modemCQ && cqCmds == "" ? " (but not enabled)" : ""));
    } else {		
	cqCmds = conf.class2CQCmd;
	if (doQuery(conf.class2CQQueryCmd, s) && FaxModem::vparseRange(s, 0, 2, &modemCQ, &sendCQ)) {
	    modemCQ >>= 1;
	    sendCQ >>= 1;
	} else {
	    modemCQ = 0;
	    sendCQ = 0;
	}
	static const char* whatCQ[4] = { "no", "checking", "correction", "checking and correction" };
	if (modemCQ)
	    modemSupports("receiving copy quality %s", whatCQ[modemCQ&3]);
	else modemSupports("no receiving copy quality services");
	if (sendCQ)
	    modemSupports("sending copy quality %s%s", whatCQ[sendCQ&3],
		(sendCQ && cqCmds == "" ? " (but not enabled)" : ""));
	else modemSupports("no sending copy quality services");
    }
    if (serviceType == SERVICE_CLASS2) {
	if (cqCmds == "") modemCQ = 0;
    } else {	
	if (cqCmds == "" && modemCQ) modemCQ = 1;
    }
    int sub = 0;
    int sep = 0;
    int pwd = 0;
    if (strcasecmp(conf.class2APQueryCmd, "none") != 0) {
	if (doQuery(conf.class2APQueryCmd, s))
	    (void) vparseRange(s, 0, 3, &sub, &sep, &pwd);
    }
    if (sub & BIT(1)) {
	saCmd = conf.class2SACmd;
	modemSupports("subaddressing");
    } else
	saCmd = "";
    if (sep & BIT(1)) {
	paCmd = conf.class2PACmd;
	modemSupports("selective polling");
    } else
	paCmd = "";
    if (pwd & BIT(1)) {
	pwCmd = conf.class2PWCmd;
	modemSupports("passwords");
    } else
	pwCmd = "";
    if ((sub|sep|pwd) & BIT(1))
	apCmd = conf.class2APCmd;
    u_int t;
    if (strcasecmp(splCmd, "none") != 0) {
	if (doQuery(splCmd | "=?", s) && FaxModem::parseRange(s, t))
	    hasPolling = (t & BIT(1)) != 0;
    }
    if (conf.class2RecvDataTrigger == "")
	recvDataTrigger = (serviceType == SERVICE_CLASS2 ? DC1 : DC2);
    else
	recvDataTrigger = conf.class2RecvDataTrigger[0];
    if ((serviceType == SERVICE_CLASS20) || (serviceType == SERVICE_CLASS21))
	xmitWaitForXON = false;
    else
	xmitWaitForXON = conf.class2XmitWaitForXON;
    if( conf.recvFillOrder == 0 &&  serviceType == SERVICE_CLASS2 ){
        if ( modemMfr.find(0, "MULTI-TECH") >= modemMfr.length()  ){
            recvFillOrder = FILLORDER_MSB2LSB;
        }
    }
    setupClass2Parameters();			
    return (true);
}
bool Class2Modem :: setupModem ( bool isSend ) { if ( ! selectBaudRate ( conf . maxRate , conf . flowControl , conf . flowControl ) ) return ( false ) ; fxStr s ; if ( doQuery ( conf . classQueryCmd , s , 5000 ) && FaxModem :: parseRange ( s , modemServices ) ) traceBits ( modemServices & SERVICE_ALL , serviceNames ) ; if ( ( modemServices & serviceType ) == 0 ) return ( false ) ; atCmd ( classCmd ) ; if ( setupManufacturer ( modemMfr ) ) { modemCapability ( " " | modemMfr ) ; modemMfr . raisecase ( ) ; } ( void ) setupModel ( modemModel ) ; ( void ) setupRevision ( modemRevision ) ; if ( modemModel != " " ) modemCapability ( " " | modemModel ) ; if ( modemRevision != " " ) modemCapability ( " " | modemRevision ) ; fxStr t30parms ; if ( ! doQuery ( dccQueryCmd , t30parms , 500 ) ) { serverTrace ( " " ) ; return ( false ) ; } if ( ! parseRange ( t30parms , modemParams ) ) { serverTrace ( " " | dccQueryCmd | " " " \" " | t30parms | " \" " ) ; return ( false ) ; } if ( conf . class2ECMType == ClassModem :: ECMTYPE_CLASS20 || ( conf . class2ECMType == ClassModem :: ECMTYPE_UNSET && serviceType != SERVICE_CLASS2 ) ) { modemParams . ec ^= BIT ( EC_DISABLE ) ; modemParams . ec <<= 1 ; modemParams . ec |= BIT ( EC_DISABLE ) ; if ( modemParams . ec & BIT ( EC_ENABLE256 ) ) modemParams . ec |= BIT ( EC_ENABLE64 ) ; } bool jbigsupported = false ; switch ( conf . class2JBIGSupport ) { case FaxModem :: JBIG_FULL : jbigsupported = true ; break ; case FaxModem :: JBIG_SEND : jbigsupported = isSend ; break ; case FaxModem :: JBIG_RECV : jbigsupported = ! isSend ; break ; } if ( ! jbigsupported ) { modemParams . df &= ~ BIT ( DF_JBIG ) ; } traceModemParams ( ) ; cqCmds = " " ; sendCQ = 0 ; if ( serviceType == SERVICE_CLASS2 ) { if ( doQuery ( conf . class2CQQueryCmd , s ) && FaxModem :: parseRange ( s , modemCQ ) ) { if ( modemCQ >>= 1 ) cqCmds = conf . class2CQCmd ; } else modemCQ = 0 ; static const char * whatCQ [ 4 ] = { " " , " " , " " , " " } ; modemSupports ( " " , whatCQ [ modemCQ & 3 ] , ( modemCQ && cqCmds == " " ? " " : " " ) ) ; } else { cqCmds = conf . class2CQCmd ; if ( doQuery ( conf . class2CQQueryCmd , s ) && FaxModem :: vparseRange ( s , 0 , 2 , & modemCQ , & sendCQ ) ) { modemCQ >>= 1 ; sendCQ >>= 1 ; } else { modemCQ = 0 ; sendCQ = 0 ; } static const char * whatCQ [ 4 ] = { " " , " " , " " , " " } ; if ( modemCQ ) modemSupports ( " " , whatCQ [ modemCQ & 3 ] ) ; else modemSupports ( " " ) ; if ( sendCQ ) modemSupports ( " " , whatCQ [ sendCQ & 3 ] , ( sendCQ && cqCmds == " " ? " " : " " ) ) ; else modemSupports ( " " ) ; } if ( serviceType == SERVICE_CLASS2 ) { if ( cqCmds == " " ) modemCQ = 0 ; } else { if ( cqCmds == " " && modemCQ ) modemCQ = 1 ; } int sub = 0 ; int sep = 0 ; int pwd = 0 ; if ( strcasecmp ( conf . class2APQueryCmd , " " ) != 0 ) { if ( doQuery ( conf . class2APQueryCmd , s ) ) ( void ) vparseRange ( s , 0 , 3 , & sub , & sep , & pwd ) ; } if ( sub & BIT ( 1 ) ) { saCmd = conf . class2SACmd ; modemSupports ( " " ) ; } else saCmd = " " ; if ( sep & BIT ( 1 ) ) { paCmd = conf . class2PACmd ; modemSupports ( " " ) ; } else paCmd = " " ; if ( pwd & BIT ( 1 ) ) { pwCmd = conf . class2PWCmd ; modemSupports ( " " ) ; } else pwCmd = " " ; if ( ( sub | sep | pwd ) & BIT ( 1 ) ) apCmd = conf . class2APCmd ; u_int t ; if ( strcasecmp ( splCmd , " " ) != 0 ) { if ( doQuery ( splCmd | " " , s ) && FaxModem :: parseRange ( s , t ) ) hasPolling = ( t & BIT ( 1 ) ) != 0 ; } if ( conf . class2RecvDataTrigger == " " ) recvDataTrigger = ( serviceType == SERVICE_CLASS2 ? DC1 : DC2 ) ; else recvDataTrigger = conf . class2RecvDataTrigger [ 0 ] ; if ( ( serviceType == SERVICE_CLASS20 ) || ( serviceType == SERVICE_CLASS21 ) ) xmitWaitForXON = false ; else xmitWaitForXON = conf . class2XmitWaitForXON ; if ( conf . recvFillOrder == 0 && serviceType == SERVICE_CLASS2 ) { if ( modemMfr . find ( 0 , " " ) >= modemMfr . length ( ) ) { recvFillOrder = FILLORDER_MSB2LSB ; } } setupClass2Parameters ( ) ; return ( true ) ; }
Check if the modem is a Class 2 modem and, if so,
 configure it for use.
Check if the modem is a Class 2 modem and if so configure it for use .
// Query service support information /*
     * Query manufacturer, model, and firmware revision.
     * We use the manufacturer especially as a key to
     * working around firmware bugs (yech!).
     */ /*
     * Get modem capabilities and calculate best signalling
     * rate, data formatting capabilities, etc. for use in
     * T.30 negotiations.
     */ /*
     * Syntax: (vr),(br),(wd),(ln),(df),(ec),(bf),(st)[,(jp)]
     * where,
     *	vr	vertical resolution
     *	br	bit rate
     *	wd	page width
     *	ln	page length
     *	df	data compression
     *	ec	error correction
     *	bf	binary file transfer
     *	st	scan time/line
     *	jp	JPEG support (optional)
     */ /*
     * The EC parameter varies between the Class 2 and Class 2.0 specs.
     * And because modems don't all adhere to the respective spec, we must adjust
     * modemParams based both on serviceType and on configuration to compensate.
     */ // The Class 2.0 spec wisely lumps both 64-byte and 256-byte ECM together // because an ECM receiver must support both anyway per T.30-A. // don't adjust EC_DISABLE // simple adjustment // reset EC_DISABLE /*
     * Check to see if the modem supports copy quality checking.
     * If the modem is capable, then enable it using the configured
     * commands.  If the modem is incapable of doing copy quality
     * checking, then the host will do the work.
     *
     * The recommendation for AT+FCQ varies significantly between
     * the Class 2 and Class 2.0 specification.
     *
     * An assumption is made that Class2CQCmd, if configured, enables
     * all available copy quality services (or disables them if none
     * are available).
     */ /*
	 * The AT+FCQ=? response indicates which compression
         * formats are copy-quality checked.
	 */ // SERVICE_CLASS20, SERVICE_CLASS21 /*
	 * The AT+FCQ=? response indicates whether or not copy-quality
         * checking and/or correction are supported.  Host CQ cannot
	 * be used if the modem performs copy-quality correction.
	 */ /*
     * In Class 2 we follow spec defaults and assume that if cqCmds is null 
     * that CQ is not enabled.  In Class 2.0/2.1 we follow spec default and
     * assume the opposite.  In order to know otherwise we'd need to make
     * sense of AT+FCQ? and incorporate that in the messages above.
     */ // SERVICE_CLASS20, SERVICE_CLASS21 /*
     * Deduce if modem supports T.class2-defined suport for
     * subaddress, selective polling address, and passwords.
     */ // some modems don't support an AP-query command /*
     * Check if the modem supports polled reception of documents.
     */ // some modems don't support an SPL command /*
     * Define the code to send to the modem to trigger the
     * transfer of received Phase C data to the host.  Most
     * modems based on SP-2388-A (Class 2) use DC1 while those
     * based on SP-2388-B (Class 2.0) use DC2.  There are some
     * exceptions (ZyXEL and modems based on Rockwell RC32ACL
     * parts), but they are expected to set the appropriate
     * value in the config file.
     */ /*
     * SP-2388-A (Class 2) specifies that the modem should send
     * XON to the host when it is ready to received page data
     * during a transmission.  This went away in SP-2388-B and in
     * the final Class 2.0 spec.  Consequently we configure the
     * modem either to ignore it (Class 2.0/2.1) or to use whatever
     * is configured (it defaults to true).
     */ /*
     * Most Class2 modems require recvFillOrder == MSB2LSB
     * (Rockwell bug, which has become "standard" now).
     *
     * The only known exception is early Multitech modems,
     * that follow original Class2 specs (LSB2MSB). They  report the
     * manufacturer as "Multi-Tech Sys" or "Multi-Tech Systems".
     *
     * Other Class2 modems that requires recvFillOrder == LSB2MSB
     * (if any) are expected to set the appropriate value in the
     * config file.
     */ // Not a Multitech // send parameters to the modem