The modemcap file

Generally speaking, our class 2 FIM relies on the modem's adherence to the
standards, but from time to time we find a modem that requires us to work
around its limitations or to enable some special capability. We have invented
the "modemcap" (modem capabilities) file that helps us describe this.  The file
is called "c2modems.ini" and is located in the $VSIFAX/lib directory.

Internally the code supports various workaround and features, and each of them
has a name that is exposed to the user via our "c2modems.ini" file. For
instance, most modems permit us to include any alphanumeric characters in a
TSI string, while others enforce the CCITT recommendations that say only
numbers/dash/plus/space.  Internally we assume a wide-open TSI, but if the
capability "strict-FLID" is set, we enforce the more restrictive rules.

Another example: all modems have a limit on how many characters can be in an
"AT" command line, and we default to a conservative 50 characters. A modem that
can accept more is more efficient because we can often turn two short sequences
into a single long one. The "max-AT-len" capability lets us set the length
appropriately.

However, doing this in the config file (which is keyed by the fax queue name)
requires way too much work on the user's part; they would have to examine the
debug logs to learn the modem information and then enter strings manually into
the file.

Instead we base our setups on the "c2modems.ini" file which is keyed on the
modem's identification strings that we get by querying the modem at startup.

This query looks like:

---> AT +FMFR?^M			manufacturer?
<--- ZyXEL
<--- OK

---> AT +FMDL?^M			model?
<--- U1496E  V 6.16 P
<--- OK

---> AT +FREV?^M			revision?
<--- U1496E  V 6.16 P
<--- OK

The "c2modems.ini" file is separated into sections just like the config file is,
and each section has a name. Unlike the config file, though, the name is
meaningless and is not used for anything other than reporting errors.
It's perfectly OK for more than one section to have the same name -- they are
still separate sections.

MODEM RECOGNITION STRINGS

The first thing to include in a section is the set of patterns that let us
recognize the modem. These help the FIM take the results of the above
manufacturer/model/revision query and associate the modem with the proper entry
from the "c2modems.ini" file. Fixed strings are usually sufficient, but we
also support regular expressions that grant wider range in selecting a pattern.
We support one kind of pattern for each of the above query strings:

	mfg-pattern = "xxx"
	mdl-pattern = "xxx"
	rev-pattern = "xxx"

Regular expressions are just like found in vi or grep and support
meta-characters that mean something beyond their usual meaning. The following
meta-characters are supported by the current regex package we're using: 

.	(dot) match any character
*	zero or more previous items
+	one or more previous items
[a-z]	single character range
[^a-z]	single character not in range
^	match start of string   (if found at the start of the pattern)
$	match end of the string (if found at the end   of the pattern)
\<	match beginning of word
\>	match end of word
\x	meta-character x is not special

For instance, 
	rev-pattern = "^7.1[234]"
matches revisions 7.12, 7.13 and 7.14 but not 7.15 or 7.0.  There are lots of
options with regular expressions, but most of the time we'll just use fixed
strings without any of the meta-characters. All patterns are matched on a
case-insensitive basis, and the pattern will match anywhere inside the string
unless you explicitly add the ^ or $ anchors.

In order to recognize a particular modem, we don't always require all three
patterns. For instance, if the model says "Courier", we don't really require
any more information to know that it's a crappy modem (at least for faxing).
As long as the section has at least one valid pattern (either mfg, mdl or rev)
we will attempt to match it, and any patterns that are missing are assumed to
match. 

Furthermore, more than one pattern is allowed for each kind of string,
something that is specifically disallowed in the config file (actually it is
allowed, but the last one read "wins"). This is most commonly used in the
"model" pattern but can be seen in any of them:

	[multi-tech]
	mfg-pattern = "multi-tech"
	mfg-pattern = "multitech"

	mdl-pattern = "2834ZDX"
	mdl-pattern = "1932ZDX"

This multiple-line rule lets us match more modems with a single section. Note
that the matches are always done in a case-insensitive manner, and the patterns
are not "anchored" at the start or the end of the string unless the user
requests this. This means that
	mfg-pattern = "foo"
will match all of:
	foo
	big foo to you
	lots of FoO

If you want to match only at the start or end of the line, you must use an
anchor:
	foo-pattern = "^foo"		only at the start of the string
	foo-pattern = "foo$"		only at the end of the string
for any of mfg/mdl/rev.

SEARCH ORDER

Ultimately the querying of the modem yields just one set of three strings,
and our job is to find which of the sections matches. Our rule is that we start
at the top of the list and match our way sequentially down and stop at the
first match even if other sections later on might match also. This does put the
burden on the user to get this right.

Some sections will be easy to define - just identify the vendor and add a few
init strings - but some will require revision-specific workarounds. It's
important to put these in the proper order lest some sections be effectively
unavailable.

For instance, if all Acme modems are supported the same way, but one particular
version of firmware has a bug we work around, put the more specific entry
earlier in the file.

	[acme with bug]
	mfg-pattern = "acme"
	rev-pattern = "^5"		# any revision starting with "5"
	workaround-bug = true		# not a real capability
	init-setup = "X4"

	[acme]
	mfg-pattern = "acme"
	init-setup = "X4"

If these are reversed, the "acme"-only pattern will match. The "mclint"
program can catch problems like this.

SETUP STRINGS

We expect that the most common addition to the "c2modems.ini" file will be
setup strings of various kinds, and we permit three of those kinds. The FIM
knows about all the standard setup strings required (no echo, verbose
responses, etc.), but some modems require a few additional setups (say, to
enable flow control and the like).

	init-setup = "XXX"
	send-setup = "XXX"
	recv-setup = "XXX"

Like the patterns above, we permit more than one of each kind of line, so each
setup can be entered on a separate line and commented (a pound sign starts a
comment). We have setups that are common to all modes (init-setup), for
sending only (send-setup) and receive modes (recv-setup). This is an example
for a Multi-Tech modem:

	init-setup      = "%E4"         ; disable TIES
	init-setup      = "&S0"         ; force DSR high (on)
	init-setup      = "X4"          ; extended result codes

(TIES is their workaround for the +++ hangup patent owned by Hayes). The
software doesn't look at the setups - it just strings them along in the places
that are appropriate.

CAPABILITY SETTINGS

The final part of each section is the most complicated and the one that
requires the most care in setup: the improper setting of a workaround or
feature capability can render the modem unusable. The great bulk of these
capabilities are Boolean, and by design all of them default to false. While
it's possible to explicitly set a capability to false, there is no point in
doing so because we don't distinguish between a "false" capability and one
that wasn't set in the first place.

multi-AT-cmds		Most modems permit us to string together multiple
			commands on a single "AT" command line, but a few
			cannot handle this. So, to be conservative we assume
			all modems are so broken and issue each command on a
			separate AT command line. This is a very safe setting
			but substantially cuts down our handshaking throughput,
			we have to wait for the modem to process and respond
			to each of the commands in our set. By setting
			multi-AT-cmds we tell the FIM to go ahead and string
			the commands together. Note that when testing a new
			modem it's always a good idea to set this first - the
			modem will either fail completely or work just fine,
			but in any case you'll probably know very quickly.

try-MT-DID		Many Multi-Tech modems support DTMF digit detection to
			support Direct Inward Dial (DID) with the "AT >DT"
			command sequence, and if this capability is true, the
			FIM will query the modem to see if this works. Normally
			any modem will just report ERROR if we try it and it's
			not supported, but we're not convinced that >DT is not
			some other command on a modem we have not heard of yet.
			So, enable this only if you believe we have a good
			chance at having it work properly.

strict-FLID		The CCITT Recommendations say that TSI and CSI strings
			are only allowed to contain digits, spaces, plus and
			dash, but most modems and fax machines support
			essentially the full printable ASCII character set.
			A few modems strictly enforce the CCITT recommendations
			and return ERROR if we try to set a local ID that does
			not conform to the rules, so this capability causes
			the FIM to prescreen the local ID before sending it to
			the modem. Note that this might completely destroy the
			TSI string if it was all alpha - there is nothing that
			the FIM can do in this case.

			Note that the class 2 spec does give a way to query
			the modem and find out what format for local ID it
			supports, but we've seen this query broken often enough
			to not bother relying on it. Note also that our default
			is not the conservative case, but it is by far the most
			common case. 

no-amperC-cmds		We normally control the modem's use of the DCD
			(carrier detect) line with the family of &Cx commands,
			where x is 0 or 1. Some loser modems claim that since
			this is not technically standard they don't have to
			support it, so we have to refrain from issuing these
			commands.

			Note: we should probably build in a query that tests
			for this to save the user from having to deal with it.

hard-flow-control	Some modems require hardware flow control.

flow-control-hard-str
flow-control-soft-str	Specify here the init string recommended by the modem's
			manufacturer to switch flow control configuration.
			The string choosed will depend on your FIM settings.

force-FBOR-0
force-FBOR-1		When dealing with binary Group 3 fax data, we have to
			know which end of the byte is sent to the other end
			first - either LSB or MSB. Most modems permit either
			"direct" or "reversed" bit order as set with the
			+FBO=n/+FBOR=n command, but a few have a problem with
			direct bit order and require us to always operate in
			the specified mode. On receive this is no big
			deal, but on transmit it occasionally means we have to
			reverse the order of the bits instead of letting the
			modem do it.  Typically this requires a developer to
			diagnose.

			Note: when you are dealing with a problem that you
			think might be related to byte ordering, please never
			add any command to an init string that sets the bit
			ordering. The FIM can support either bit order, but
			it must know which one is being used - setting the
			value in an init string goes "behind" the FIM and
			will only break things. Don't ever do it.

			Note that if either of these are specified, then the
			+FBO=?/+FBOR=? query will not be issued.

reversed-recv-FBOR	Some modems (Lucent / Multitech) actually reverse the
			sense of +FBOR values (0=MSB and 1=LSB -- this is
			backwards). This entry deals with that.

ignore-rcv-FF		Some modems stream a bunch of FF bytes prior to
			the actual data.  This tells us to ignore them.

FPS-nothex		In class 2.0 devices, the modem gives us a "+FPS"
			response when receiving a page that indicates the
			number of scanlines, number of bytes, number of bad
			lines, and the like. These numbers are supposed to be
			in hexadecimal, but some modems (Courier) simply get
			this wrong and provide the data in decimal. This is
			clearly a modem bug, and we account for it by setting
			this capability to true.

no-FBS-query		When we first initialize the modem we perform lots of
			queries to see what it supports, and this includes a
			query of the buffer size (+FBUF=?/+FBS=?). Some modems
			have a bug where we cannot even ask for the buffer
			size - they go out to lunch. This is mainly found in a
			few revisions of Zyxel modems but can be used anywhere
			required.

no-FEA-query		Same as above but for the +FEA capability that informs
			us of the modem's ability to pad out each scanline so
			the EOL is aligned on a byte boundary. Note that our
			software doesn't care about received EOL alignment -
			too many modems won't do it right - so we don't use
			+FREL/+FEA in the code any longer. This capability
			will probably go away.

no-FCQ-query		Same as above but for the +FCQ capability that informs
			us of the modem's ability to perform copy quality
			checking and fixing on both send and receive.

no-FAA-query		Same as above but for the +FAA capability that informs
			us of the modem's ability to perform adaptive
			answering.

no-FCR-query		Same as above but for the +FCR capability that informs
			us of the modem's ability to receive.

no-FFC-query		Same as above but for the +FVRFC/+FFC capability that
			informs us of the modem's ability to perform vertical
			resolution format conversions.

disable-class-2		Some modems support both class 2 and class 2.0, but
			sometimes we observe that one of the modes operates
			better than the other one. By setting this flag, a
			dual-class modem will not attempt to use class 2 and
			will try to use class 2.x if it's available. Note
			that setting this capability on a class2-only modem
			will cause the FIM to fail to initialize.

disable-class-2.0	Same as above, but for class 2.0 instead.
			Note that disabling 2.0 support also disables
			2.1 support.

disable-class-2.1	Same as above, but for class 2.1 instead.

no-support		Some modems are so hopelessly broken that we have no
			chance of making them work at all. If we have
			identified this (usually for a particular version of
			firmware) setting this variable to true causes the FIM
			to gracefully fail after sending a note to the log that
			we cannot support this modem at all. See also the
			"message" string capability below.

cannot-recv		Some modems are so badly broken that receiving a fax
			is simply not possible, so this capability informs the
			FIM to not bother and to never answer the phone. The
			scheduler may still show the FIM with receive enabled,
			but the modem won't ever actually do it.

fulltime-CLOCAL		This is a carryover from the UNIX FIMs that need to
			specifically support carrier-detect at the operating
			system level. We don't currently use this but may do
			so later.

max-AT-len		All modems have some kind of limit on the length of an
			AT command line they will accept before issuing an
			ERROR message, and the FIM software is constrained to
			never issue a command line longer than this. At
			startup we assume a conservative 50 character limit,
			but for modems that we know can take more, we can set
			this numeric capability to the longer amount. It's
			best to try to set the longest valid length, because
			this causes the FIM to operate faster because it can
			sometimes issue one single long command instead of two
			separate shorter ones.

			Note that unless multi-AT-cmds is set this capability
			is not effectively used.

message			This is a generic string message that is dumped into
			the log after query time and can give explanations of
			problems we know the modem will be having. For
			instance, if "cannot-recv" is set, perhaps it would be
			best to place a message into the file mentioning this
			(perhaps describe the version of firmware that
			fixes the problem). More than one of these capabilities
			is permitted, and they are dumped in order.

dtmf-query-str		AT command used to query modem's DTMF capabilities.
			Default value is ">DT1 H".

dtmf-use-voice-mode	Set this value when voice need to be used for DTMF
			capabilities. In voice mode, a <DLE> character should
			precede each event produced by the modem.
 
dtmf-mode-on-str	AT command used to make the modem ready to receive DTMF
			codes. Default value is "H1>DT1".

dtmf-mode-off-str	AT command used to make the modem ready to receive fax
			data. Use special mode "FAXMODE" to go back to fax receipt
			mode (using "AT+FCLASS=") and ready to receive data.
			Default value is ">DT0A".

DEBUG LOG SUPPORT

The C2 FIM loads this modemcap file at startup and performs a query to the
modem. Once we have the query strings, the modemcap database is consulted.
If we find a modemcap entry for this modem, we dump a note to the log that
gives the section name, source (file or compiled-in text), starting line
number, and a copy of all the parameters to the debug log.  Note that we only
display parameters that are true, because false parameters are the same as
unset parameters.

If we don't find a modemcap setup for this modem - this is normal - we note
this in the logs so that tech support knows that nothing special is going on.

