ModemConfig.c++
上传用户:weiyuanprp
上传日期:2020-05-20
资源大小:1169k
文件大小:29k
源码类别:

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: ModemConfig.c++,v 1.35 2008/09/30 05:33:27 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1990-1996 Sam Leffler
  4.  * Copyright (c) 1991-1996 Silicon Graphics, Inc.
  5.  * HylaFAX is a trademark of Silicon Graphics
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and 
  8.  * its documentation for any purpose is hereby granted without fee, provided
  9.  * that (i) the above copyright notices and this permission notice appear in
  10.  * all copies of the software and related documentation, and (ii) the names of
  11.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  12.  * publicity relating to the software without the specific, prior written
  13.  * permission of Sam Leffler and Silicon Graphics.
  14.  * 
  15.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18.  * 
  19.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  20.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  21.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  23.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  24.  * OF THIS SOFTWARE.
  25.  */
  26. #include "ModemConfig.h"
  27. #include "t.30.h"
  28. #include "config.h"
  29. #include "tiffio.h"
  30. #include <ctype.h>
  31. #define N(a) (sizeof (a) / sizeof (a[0]))
  32. ModemConfig::ModemConfig()
  33. {
  34.     setupConfig();
  35. }
  36. ModemConfig::~ModemConfig()
  37. {
  38. }
  39. const fxStr&
  40. ModemConfig::getFlowCmd(FlowControl f) const
  41. {
  42.     if (f == ClassModem::FLOW_RTSCTS)
  43. return (hardFlowCmd);
  44.     else if (f == ClassModem::FLOW_XONXOFF)
  45. return (softFlowCmd);
  46.     else if (f == ClassModem::FLOW_NONE)
  47. return (noFlowCmd);
  48.     else
  49. return (fxStr::null);
  50. }
  51. /*
  52.  * The following tables map configuration parameter names to
  53.  * pointers to class ModemConfig members and provide default
  54.  * values that are forced when the configuration is reset
  55.  * prior to reading a configuration file.
  56.  */
  57. /*
  58.  * Note that all of the Class 2/2.0 parameters except
  59.  * Class2CQQueryCmd are initialized at the time the
  60.  * modem is setup based on whether the modem is Class 2
  61.  * or Class 2.0.
  62.  */
  63. static struct {
  64.     const char*  name;
  65.     fxStr ModemConfig::* p;
  66.     const char*  def; // NULL is shorthand for ""
  67. } atcmds[] = {
  68. { "modemanswercmd", &ModemConfig::answerAnyCmd, "ATA" },
  69. { "modemansweranycmd", &ModemConfig::answerAnyCmd },
  70. { "modemanswerfaxcmd", &ModemConfig::answerFaxCmd },
  71. { "modemanswerdatacmd", &ModemConfig::answerDataCmd },
  72. { "modemanswervoicecmd", &ModemConfig::answerVoiceCmd },
  73. { "modemanswerdialcmd", &ModemConfig::answerDialCmd },
  74. { "modemanswerfaxbegincmd", &ModemConfig::answerFaxBeginCmd },
  75. { "modemanswerdatabegincmd", &ModemConfig::answerDataBeginCmd },
  76. { "modemanswervoicebegincmd", &ModemConfig::answerVoiceBeginCmd },
  77. { "modemringresponse", &ModemConfig::ringResponse },
  78. { "modemresetcmds", &ModemConfig::resetCmds },
  79. { "modemreadycmds", &ModemConfig::readyCmds },
  80. { "modemdialcmd", &ModemConfig::dialCmd, "ATDT%s" },
  81. { "modemsetorigincmd", &ModemConfig::setOriginCmd },
  82. { "modemnoflowcmd", &ModemConfig::noFlowCmd },
  83. { "modemsoftflowcmd", &ModemConfig::softFlowCmd },
  84. { "modemhardflowcmd", &ModemConfig::hardFlowCmd },
  85. { "modemsetupaacmd", &ModemConfig::setupAACmd },
  86. { "modemsetupdtrcmd", &ModemConfig::setupDTRCmd },
  87. { "modemsetupdcdcmd", &ModemConfig::setupDCDCmd },
  88. { "modemnoautoanswercmd", &ModemConfig::noAutoAnswerCmd, "ATS0=0" },
  89. { "modemechooffcmd", &ModemConfig::echoOffCmd, "ATE0" },
  90. { "modemverboseresultscmd", &ModemConfig::verboseResultsCmd,"ATV1" },
  91. { "modemresultcodescmd", &ModemConfig::resultCodesCmd, "ATQ0" },
  92. { "modemonhookcmd", &ModemConfig::onHookCmd, "ATH0" },
  93. { "modemsoftresetcmd", &ModemConfig::softResetCmd, "ATZ" },
  94. { "modemwaittimecmd", &ModemConfig::waitTimeCmd, "ATS7=60" },
  95. { "modemcommapausetimecmd", &ModemConfig::pauseTimeCmd, "ATS8=2" },
  96. { "modemmfrquerycmd", &ModemConfig::mfrQueryCmd },
  97. { "modemmodelquerycmd", &ModemConfig::modelQueryCmd },
  98. { "modemrevquerycmd", &ModemConfig::revQueryCmd },
  99. { "modemsendbegincmd", &ModemConfig::sendBeginCmd },
  100. { "modemrecvsuccesscmd", &ModemConfig::recvSuccessCmd },
  101. { "modemclassquerycmd", &ModemConfig::classQueryCmd, "AT+FCLASS=?" },
  102. { "class0cmd", &ModemConfig::class0Cmd, "AT+FCLASS=0" },
  103. { "class1cmd", &ModemConfig::class1Cmd },
  104. { "class1adaptrecvcmd", &ModemConfig::class1AdaptRecvCmd },
  105. { "class1enablev34cmd", &ModemConfig::class1EnableV34Cmd },
  106. { "class1nflocmd", &ModemConfig::class1NFLOCmd },
  107. { "class1sflocmd", &ModemConfig::class1SFLOCmd },
  108. { "class1hflocmd", &ModemConfig::class1HFLOCmd },
  109. { "class1ppmwaitcmd", &ModemConfig::class1PPMWaitCmd, "AT+FTS=7" },
  110. { "class1responsewaitcmd", &ModemConfig::class1ResponseWaitCmd, "" },
  111. { "class1rmquerycmd", &ModemConfig::class1RMQueryCmd, "AT+FRM=?" },
  112. { "class1tcfwaitcmd", &ModemConfig::class1TCFWaitCmd, "AT+FTS=7" },
  113. { "class1tmquerycmd", &ModemConfig::class1TMQueryCmd, "AT+FTM=?" },
  114. { "class1eopwaitcmd", &ModemConfig::class1EOPWaitCmd, "AT+FTS=9" },
  115. { "class1msgrecvhackcmd", &ModemConfig::class1MsgRecvHackCmd, "" },
  116. { "class1tcfrecvhackcmd", &ModemConfig::class1TCFRecvHackCmd, "" },
  117. { "class1switchingcmd", &ModemConfig::class1SwitchingCmd, "AT+FRS=7" },
  118. { "class2cmd", &ModemConfig::class2Cmd },
  119. { "class2borcmd", &ModemConfig::class2BORCmd },
  120. { "class2disablev17cmd", &ModemConfig::class2DisableV17Cmd },
  121. { "class2disablev34cmd", &ModemConfig::class2DisableV34Cmd },
  122. { "class2relcmd", &ModemConfig::class2RELCmd },
  123. { "class2cqcmd", &ModemConfig::class2CQCmd },
  124. { "class2abortcmd", &ModemConfig::class2AbortCmd },
  125. { "class2cqquerycmd",     &ModemConfig::class2CQQueryCmd, "AT+FCQ=?" },
  126. { "class2dccquerycmd", &ModemConfig::class2DCCQueryCmd },
  127. { "class2tbccmd", &ModemConfig::class2TBCCmd },
  128. { "class2crcmd", &ModemConfig::class2CRCmd },
  129. { "class2phctocmd", &ModemConfig::class2PHCTOCmd },
  130. { "class2bugcmd", &ModemConfig::class2BUGCmd },
  131. { "class2lidcmd", &ModemConfig::class2LIDCmd },
  132. { "class2dcccmd", &ModemConfig::class2DCCCmd },
  133. { "class2discmd", &ModemConfig::class2DISCmd },
  134. { "class2ddiscmd", &ModemConfig::class2DDISCmd },
  135. { "class2cigcmd", &ModemConfig::class2CIGCmd },
  136. { "class2ptscmd", &ModemConfig::class2PTSCmd },
  137. { "class2ptsquerycmd", &ModemConfig::class2PTSQueryCmd, "AT+FPS?" },
  138. { "class2splcmd", &ModemConfig::class2SPLCmd },
  139. { "class2piecmd", &ModemConfig::class2PIECmd },
  140. { "class2nrcmd", &ModemConfig::class2NRCmd },
  141. { "class2nflocmd", &ModemConfig::class2NFLOCmd },
  142. { "class2sflocmd", &ModemConfig::class2SFLOCmd },
  143. { "class2hflocmd", &ModemConfig::class2HFLOCmd },
  144. { "class2minspcmd", &ModemConfig::class2MINSPCmd },
  145. { "class2apquerycmd", &ModemConfig::class2APQueryCmd, "AT+FAP=?" },
  146. { "class2apcmd", &ModemConfig::class2APCmd, "AT+FAP" },
  147. { "class2sacmd", &ModemConfig::class2SACmd, "AT+FSA" },
  148. { "class2pacmd", &ModemConfig::class2PACmd, "AT+FPA" },
  149. { "class2pwcmd", &ModemConfig::class2PWCmd, "AT+FPW" },
  150. };
  151. static struct {
  152.     const char*  name;
  153.     fxStr ModemConfig::* p;
  154.     const char*  def; // NULL is shorthand for ""
  155. } strcmds[] = {
  156. { "modemtype", &ModemConfig::type, "unknown" },
  157. { "taglinefont", &ModemConfig::tagLineFontFile },
  158. { "taglinelocale", &ModemConfig::tagLineLocale, "" },
  159. { "taglineformat", &ModemConfig::tagLineFmt,
  160.   "From %%n|%c|Page %%p of %%t" },
  161. { "tiff2faxcmd", &ModemConfig::tiff2faxCmd, FAX_TIFF2FAXCMD },
  162. { "class2recvdatatrigger", &ModemConfig::class2RecvDataTrigger },
  163. { "ringdata", &ModemConfig::ringData },
  164. { "ringfax", &ModemConfig::ringFax },
  165. { "ringvoice", &ModemConfig::ringVoice },
  166. { "ringextended", &ModemConfig::ringExtended },
  167. { "dringon", &ModemConfig::dringOn  },
  168. { "dringoff", &ModemConfig::dringOff  },
  169. };
  170. static struct {
  171.     const char*  name;
  172.     u_int ModemConfig::* p;
  173.     u_int  def;
  174. } fillorders[] = {
  175. { "modemrecvfillorder",  &ModemConfig::recvFillOrder,  0 }, // will be autodetected
  176. { "modemsendfillorder",  &ModemConfig::sendFillOrder,  0 }, // will be autodetected
  177. { "modemframefillorder", &ModemConfig::frameFillOrder, FILLORDER_LSB2MSB },
  178. };
  179. static struct {
  180.     const char*  name;
  181.     u_int ModemConfig::* p;
  182.     u_int  def;
  183. } numbers[] = {
  184. { "ringtimeout", &ModemConfig::ringTimeout,      6000 },
  185. { "percentgoodlines", &ModemConfig::percentGoodLines,      95 },
  186. { "maxconsecutivebadlines", &ModemConfig::maxConsecutiveBadLines,5 },
  187. { "minacceptedlinecount", &ModemConfig::minAcceptedLineCount,  10 },
  188. { "modemresetdelay", &ModemConfig::resetDelay,      2600 },
  189. { "modemdtrdropdelay", &ModemConfig::dtrDropDelay,      75 },
  190. { "modembaudratedelay", &ModemConfig::baudRateDelay,      10 },
  191. { "modematcmddelay", &ModemConfig::atCmdDelay,      0 },
  192. { "faxt1timer", &ModemConfig::t1Timer,      TIMER_T1 },
  193. { "faxt2timer", &ModemConfig::t2Timer,      TIMER_T2 },
  194. { "faxt4timer", &ModemConfig::t4Timer,      TIMER_T4 },
  195. { "modemdialresponsetimeout", &ModemConfig::dialResponseTimeout,   3*60*1000},
  196. { "modemanswerresponsetimeout", &ModemConfig::answerResponseTimeout, 3*60*1000},
  197. { "modempagestarttimeout", &ModemConfig::pageStartTimeout,      3*60*1000},
  198. { "modempagedonetimeout", &ModemConfig::pageDoneTimeout,      3*60*1000},
  199. { "modemringsbeforeresponse", &ModemConfig::ringsBeforeResponse,   0 },
  200. { "modemsoftresetcmddelay", &ModemConfig::softResetCmdDelay,     3000 },
  201. { "modemnoautoanswercmddelay", &ModemConfig::noAutoAnswerCmdDelay,  0 },
  202. { "class1tcfrecvtimeout", &ModemConfig::class1TCFRecvTimeout,  4500 },
  203. { "class1recvabortok", &ModemConfig::class1RecvAbortOK,     200 },
  204. { "class1rmpersistence", &ModemConfig::class1RMPersistence,   2 },
  205. { "class1hooksensitivity", &ModemConfig::class1HookSensitivity, 0 },
  206. { "class1frameoverhead", &ModemConfig::class1FrameOverhead,   4 },
  207. { "class1recvidenttimer", &ModemConfig::class1RecvIdentTimer,  TIMER_T1 },
  208. { "class1tcfmaxnonzero", &ModemConfig::class1TCFMaxNonZero,   10 },
  209. { "class1tcfminrun", &ModemConfig::class1TCFMinRun,       (2*TCF_DURATION)/3 },
  210. { "class1tcfminrunecmmod", &ModemConfig::class1TCFMinRunECMMod, 2 },
  211. { "class1tmconnectdelay", &ModemConfig::class1TMConnectDelay,  0 },
  212. { "class1ecmframesize", &ModemConfig::class1ECMFrameSize,    256 },
  213. { "class1pagelengthsupport", &ModemConfig::class1PageLengthSupport, LN_ALL },
  214. { "class1pagewidthsupport", &ModemConfig::class1PageWidthSupport, WD_ALL },
  215. };
  216. static struct {
  217.     const char*  name;
  218.     bool ModemConfig::* p;
  219.     bool  def;
  220. } booleans[] = {
  221. { "usejobtagline", &ModemConfig::useJobTagLine, true },
  222. { "modemwaitforconnect", &ModemConfig::useJobTagLine, false },
  223. { "modemraiseatcommands", &ModemConfig::raiseATCmd, true },
  224. { "class2xmitwaitforxon", &ModemConfig::class2XmitWaitForXON, true },
  225. { "class2sendrtc", &ModemConfig::class2SendRTC, false },
  226. { "class2rtfcc", &ModemConfig::class2RTFCC, false },
  227. { "class2usehex", &ModemConfig::class2UseHex, false },
  228. { "class2hexnsf", &ModemConfig::class2HexNSF, true },
  229. { "class2uselinecount", &ModemConfig::class2UseLineCount, false },
  230. #ifdef PHOTOMETRIC_ITULAB
  231. { "class1greyjpegsupport", &ModemConfig::class1GreyJPEGSupport, false },
  232. { "class1colorjpegsupport", &ModemConfig::class1ColorJPEGSupport, false },
  233. { "class2jpegsupport", &ModemConfig::class2JPEGSupport, false },
  234. #endif
  235. { "class1ecmsupport", &ModemConfig::class1ECMSupport, true },
  236. { "class1mrsupport", &ModemConfig::class1MRSupport, true },
  237. { "class1mmrsupport", &ModemConfig::class1MMRSupport, true },
  238. { "class1persistentecm", &ModemConfig::class1PersistentECM, true },
  239. { "class1validatev21frames", &ModemConfig::class1ValidateV21Frames, false },
  240. { "class1modemhasdlebug", &ModemConfig::class1ModemHasDLEBug, false },
  241. { "class1hasrhconnectbug", &ModemConfig::class1HasRHConnectBug, false },
  242. { "saveunconfirmedpages", &ModemConfig::saveUnconfirmedPages, true },
  243. { "modemsoftrtfcc", &ModemConfig::softRTFCC, true },
  244. { "modemdophasecdebug", &ModemConfig::doPhaseCDebug, false },
  245. { "noanswervoice", &ModemConfig::noAnswerVoice, false },
  246. { "saverawimage", &ModemConfig::saverawimage, false },
  247. };
  248. void
  249. ModemConfig::setupConfig()
  250. {
  251.     int i;
  252.     for (i = N(atcmds)-1; i >= 0; i--)
  253. (*this).*atcmds[i].p = (atcmds[i].def ? atcmds[i].def : "");
  254.     for (i = N(strcmds)-1; i >= 0; i--)
  255. (*this).*strcmds[i].p = (strcmds[i].def ? strcmds[i].def : "");
  256.     for (i = N(fillorders)-1; i >= 0; i--)
  257. (*this).*fillorders[i].p = fillorders[i].def;
  258.     for (i = N(numbers)-1; i >= 0; i--)
  259. (*this).*numbers[i].p = numbers[i].def;
  260.     for (i = N(booleans)-1; i >= 0; i--)
  261. (*this).*booleans[i].p = booleans[i].def;
  262.     for (i=0; i < 5; ++i) {
  263.      distinctiveRings[i].type = ClassModem::CALLTYPE_UNKNOWN;
  264. for (u_int j=0; j < 5; ++j)
  265.     distinctiveRings[i].cadence[j] = 0;
  266. distinctiveRings[i].magsqrd = 0;
  267.     }
  268.     flowControl         = ClassModem::FLOW_XONXOFF;// software flow control
  269.     maxRate = ClassModem::BR19200; // reasonable for most modems
  270.     minSpeed = BR_2400; // minimum transmit speed
  271.     class2ECMType = ClassModem::ECMTYPE_UNSET;// follow the service type default
  272. #ifdef HAVE_JBIG
  273. #ifdef HAVE_JBIGTIFF
  274.     class1JBIGSupport = FaxModem::JBIG_FULL; // full support for monochrome JBIG
  275.     class2JBIGSupport = FaxModem::JBIG_FULL; // full support for monochrome JBIG
  276. #else
  277.     class1JBIGSupport = FaxModem::JBIG_SEND; // send support for monochrome JBIG
  278.     class2JBIGSupport = FaxModem::JBIG_SEND; // send support for monochrome JBIG
  279. #endif
  280. #else
  281. #ifdef HAVE_JBIGTIFF
  282.     class1JBIGSupport = FaxModem::JBIG_RECV; // receive support for monochrome JBIG
  283.     class2JBIGSupport = FaxModem::JBIG_RECV; // receive support for monochrome JBIG
  284. #else
  285.     class1JBIGSupport = FaxModem::JBIG_NONE; // no support for monochrome JBIG
  286.     class2JBIGSupport = FaxModem::JBIG_NONE; // no support for monochrome JBIG
  287. #endif
  288. #endif
  289.     class1Resolutions = VR_ALL; // resolutions support
  290.     setVolumeCmds("ATM0 ATL0M1 ATL1M1 ATL2M1 ATL3M1");
  291.     recvDataFormat = DF_ALL; // default to no transcoding
  292.     rtnHandling         = FaxModem::RTN_RETRANSMITIGNORE; // retransmit until MCF/MPS
  293.     badPageHandling = FaxModem::BADPAGE_RTNSAVE; // send RTN but save the page
  294.     idConfig.resize(0);
  295.     callidIndex = (u_int) -1;
  296. }
  297. void
  298. ModemConfig::resetConfig()
  299. {
  300.     FaxConfig::resetConfig();
  301.     setupConfig();
  302. }
  303. #define valeq(a,b) (strcasecmp(a,b)==0)
  304. bool
  305. ModemConfig::findRate(const char* cp, BaudRate& br)
  306. {
  307.     static const struct {
  308. const char* name;
  309. BaudRate    b;
  310.     } rates[] = {
  311. {    "300", ClassModem::BR300 },
  312. {   "1200", ClassModem::BR1200 },
  313. {   "2400", ClassModem::BR2400 },
  314. {   "4800", ClassModem::BR4800 },
  315. {   "9600", ClassModem::BR9600 },
  316. {  "19200", ClassModem::BR19200 },
  317. {  "38400", ClassModem::BR38400 },
  318. {  "57600", ClassModem::BR57600 },
  319. {  "76800", ClassModem::BR76800 },
  320. { "115200", ClassModem::BR115200 },
  321.     };
  322.     for (int i = N(rates)-1; i >= 0; i--)
  323. if (streq(cp, rates[i].name)) {
  324.     br = rates[i].b;
  325.     return (true);
  326. }
  327.     return (false);
  328. }
  329. BaudRate
  330. ModemConfig::getRate(const char* cp)
  331. {
  332.     BaudRate br;
  333.     if (!findRate(cp, br)) {
  334. configError("Unknown baud rate "%s", using 19200", cp);
  335. br = ClassModem::BR19200; // default
  336.     }
  337.     return (br);
  338. }
  339. ECMType
  340. ModemConfig::getECMType(const char* cp)
  341. {
  342.     if (valeq(cp, "2"))
  343. return (ClassModem::ECMTYPE_CLASS2);
  344.     if (valeq(cp, "2.0"))
  345. return (ClassModem::ECMTYPE_CLASS20);
  346.     configError("Unknown ECM type specification "%s", using default", cp);
  347.     return (ClassModem::ECMTYPE_UNSET);
  348. }
  349. bool
  350. ModemConfig::findATResponse(const char* cp, ATResponse& resp)
  351. {
  352.     static const struct {
  353. const char* name;
  354. ATResponse  r;
  355.     } responses[] = {
  356. {    "NOTHING", ClassModem::AT_NOTHING },
  357. {         "OK", ClassModem::AT_OK },
  358. {    "CONNECT", ClassModem::AT_CONNECT },
  359. {   "NOANSWER", ClassModem::AT_NOANSWER },
  360. {  "NOCARRIER", ClassModem::AT_NOCARRIER },
  361. { "NODIALTONE", ClassModem::AT_NODIALTONE },
  362. {       "BUSY", ClassModem::AT_BUSY },
  363. {    "OFFHOOK", ClassModem::AT_OFFHOOK },
  364. {       "RING", ClassModem::AT_RING },
  365. {      "ERROR", ClassModem::AT_ERROR },
  366. {       "VCON", ClassModem::AT_VCON },
  367. {      "OTHER", ClassModem::AT_OTHER },
  368.     };
  369.     for (u_int i = 0; i < N(responses); i++)
  370. if (valeq(cp, responses[i].name)) {
  371.     resp = responses[i].r;
  372.     return (true);
  373. }
  374.     return (false);
  375. }
  376. u_int
  377. ModemConfig::getFill(const char* cp)
  378. {
  379.     if (valeq(cp, "LSB2MSB"))
  380. return (FILLORDER_LSB2MSB);
  381.     else if (valeq(cp, "MSB2LSB"))
  382. return (FILLORDER_MSB2LSB);
  383.     else {
  384. configError("Unknown fill order "%s"", cp);
  385.         return ((u_int) -1);
  386.     }
  387. }
  388. bool
  389. ModemConfig::findFlow(const char* cp, FlowControl& fc)
  390. {
  391.     static const struct {
  392. const char* name;
  393. FlowControl f;
  394.     } fcnames[] = {
  395. { "XONXOFF", ClassModem::FLOW_XONXOFF },
  396. {  "RTSCTS", ClassModem::FLOW_RTSCTS },
  397. {    "NONE", ClassModem::FLOW_NONE },
  398. {     "XON", ClassModem::FLOW_XONXOFF },
  399. {     "RTS", ClassModem::FLOW_RTSCTS },
  400.     };
  401.     for (u_int i = 0; i < N(fcnames); i++)
  402. if (valeq(cp, fcnames[i].name)) {
  403.     fc = fcnames[i].f;
  404.     return (true);
  405. }
  406.     return (false);
  407. }
  408. FlowControl
  409. ModemConfig::getFlow(const char* cp)
  410. {
  411.     FlowControl fc;
  412.     if (!findFlow(cp, fc)) {
  413. configError("Unknown flow control "%s", using xonxoff", cp);
  414. fc = ClassModem::FLOW_XONXOFF; // default
  415.     }
  416.     return (fc);
  417. }
  418. void
  419. ModemConfig::setVolumeCmds(const fxStr& tag)
  420. {
  421.     u_int l = 0;
  422.     for (int i = ClassModem::OFF; i <= ClassModem::HIGH; i++)
  423. setVolumeCmd[i] = parseATCmd(tag.token(l, " t"));
  424. }
  425. /*
  426.  * Scan AT command strings and convert <...> escape
  427.  * commands into single-byte escape codes that are
  428.  * interpreted by ClassModem::atCmd.  Note that the
  429.  * baud rate setting commands are carefully ordered
  430.  * so that the desired baud rate can be extracted
  431.  * from the low nibble.
  432.  */
  433. fxStr
  434. ModemConfig::parseATCmd(const char* cp)
  435. {
  436.     fxStr cmd(cp);
  437.     u_int pos = 0;
  438.     while ((pos = cmd.next(pos, '<')) != cmd.length()) {
  439. u_int epos = pos+1;
  440. fxStr esc = cmd.token(epos, '>');
  441. esc.lowercase();
  442. FlowControl fc;
  443. BaudRate br;
  444. u_char ecode[2];
  445. if (findFlow(esc, fc)) {
  446.     ecode[0] = ESC_SETFLOW;
  447.     ecode[1] = (u_char) fc;
  448. } else if (findRate(esc, br)) {
  449.     ecode[0] = ESC_SETBR;
  450.     ecode[1] = (u_char) br;
  451. } else if (esc == "flush") {
  452.     cmd.remove(pos, epos-pos);
  453.     cmd.insert(ESC_FLUSH, pos);
  454.     continue;
  455. } else if (esc == "") { // NB: "<>" => <
  456.     cmd.remove(pos, epos-pos);
  457.     cmd.insert('<', pos);
  458.     continue;
  459. } else if (esc.length() > 6 && strneq(esc, "delay:", 6)) {
  460.     u_int delay = (u_int) atoi(&esc[6]);
  461.     if (delay > 255) {
  462. configError("Bad AT delay value "%s", must be <256", &esc[6]);
  463. pos = epos;
  464. continue;
  465.     }
  466.     ecode[0] = ESC_DELAY;
  467.     ecode[1] = (u_char) delay;
  468. } else if (esc.length() > 8 && strneq(esc, "waitfor:", 8)) {
  469.     ATResponse resp;
  470.     if (!findATResponse(&esc[8], resp)) {
  471. configError("Unknown AT response code "%s"", &esc[8]);
  472. pos = epos;
  473. continue;
  474.     }
  475.     ecode[0] = ESC_WAITFOR;
  476.     ecode[1] = (u_char) resp;
  477. } else if (esc.length() > 5 && strneq(esc, "play:", 5)) {
  478.     ecode[0] = ESC_PLAY;
  479.     ecode[1] = (u_char) esc[5];
  480. } else {
  481.     configError("Unknown AT escape code "%s"", (const char*) esc);
  482.     pos = epos;
  483.     continue;
  484. }
  485. cmd.remove(pos, epos-pos);
  486. cmd.insert((char*) ecode, pos, 2);
  487. pos += 2; // don't try parsing our newly inserted ecode
  488.     }
  489.     return (cmd);
  490. }
  491. u_int
  492. ModemConfig::getSpeed(const char* value)
  493. {
  494.     switch (atoi(value)) {
  495.     case 2400: return (BR_2400);
  496.     case 4800: return (BR_4800);
  497.     case 7200: return (BR_7200);
  498.     case 9600: return (BR_9600);
  499.     case 12000: return (BR_12000);
  500.     case 14400: return (BR_14400);
  501.     case 16800: return (BR_16800);
  502.     case 19200: return (BR_19200);
  503.     case 21600: return (BR_21600);
  504.     case 24000: return (BR_24000);
  505.     case 26400: return (BR_26400);
  506.     case 28800: return (BR_28800);
  507.     case 31200: return (BR_31200);
  508.     case 33600: return (BR_33600);
  509.     }
  510.     configError("Invalid minimum transmit speed "%s"", value);
  511.     return (BR_2400);
  512. }
  513. bool
  514. ModemConfig::findDataFormat(const char* cp, u_int& df)
  515. {
  516.     static const struct {
  517. const char* name;
  518. u_int d;
  519.     } dfnames[] = {
  520. {       "1DMH", DF_1DMH },
  521. {       "2DMR", DF_2DMR },
  522. { "2DMRUNCOMP", DF_2DMRUNCOMP },
  523. {      "2DMMR", DF_2DMMR },
  524. {   "adaptive", DF_ALL },
  525.     };
  526.     char v[30];
  527.     u_int i = 0;
  528.     for (; *cp; cp++) {
  529. if (*cp == '-' || isspace(*cp)) // strip ``-'' and white space
  530.     continue;
  531. if (i >= sizeof (v))
  532.     break;
  533. v[i++] = *cp;
  534.     }
  535.     v[i] = '';
  536.     for (i = 0; i < N(dfnames); i++)
  537. if (valeq(v, dfnames[i].name)) {
  538.     df = dfnames[i].d;
  539.     return (true);
  540. }
  541.     return (false);
  542. }
  543. u_int
  544. ModemConfig::getDataFormat(const char* cp)
  545. {
  546.     u_int df;
  547.     if (!findDataFormat(cp, df)) {
  548. configError("Unknown data format "%s", disabling transcoding", cp);
  549. df = DF_ALL; // default
  550.     }
  551.     return (df);
  552. }
  553. bool
  554. ModemConfig::findRTNHandling(const char* cp, RTNHandling& rh)
  555. {
  556.     static const struct {
  557.         const char* name;
  558.         RTNHandling rh;
  559.     } rhnames[] = {
  560.         { "RETRANSMIT", FaxModem::RTN_RETRANSMIT },
  561.         {     "GIVEUP", FaxModem::RTN_GIVEUP },
  562.         {     "IGNORE", FaxModem::RTN_IGNORE },
  563.         { "RETRANSMIT-IGNORE", FaxModem::RTN_RETRANSMITIGNORE }
  564.     };
  565.     for (u_int i = 0; i < N(rhnames); i++)
  566.         if (valeq(cp, rhnames[i].name)) {
  567.             rh = rhnames[i].rh;
  568.             return (true);
  569.         }
  570.     return (false);
  571. }
  572. u_int
  573. ModemConfig::getRTNHandling(const char* cp)
  574. {
  575.     RTNHandling rh;
  576.     if (!findRTNHandling(cp, rh)) {
  577.         configError("Unknown RTN handling method "%s", using RETRANSMIT-IGNORE", cp);
  578.         rh = FaxModem::RTN_RETRANSMITIGNORE;   // default
  579.     }
  580.     return (rh);
  581. }
  582. u_int
  583. ModemConfig::getBadPageHandling(const char* cp)
  584. {
  585.     BadPageHandling bph;
  586.     if (valeq(cp, "RTN")) {
  587. bph = FaxModem::BADPAGE_RTN;
  588.     } else if (valeq(cp, "DCN")) {
  589. bph = FaxModem::BADPAGE_DCN;
  590.     } else {
  591. bph = FaxModem::BADPAGE_RTNSAVE;
  592.     }
  593.     return (bph);
  594. }
  595. u_int
  596. ModemConfig::getJBIGSupport(const char* cp)
  597. {
  598.     JBIGSupport js;
  599.     if (valeq(cp, "FULL")) {
  600. js = FaxModem::JBIG_FULL;
  601.     } else if (valeq(cp, "YES")) {
  602. js = FaxModem::JBIG_FULL;
  603.     } else if (valeq(cp, "TRUE")) {
  604. js = FaxModem::JBIG_FULL;
  605.     } else if (valeq(cp, "NONE")) {
  606. js = FaxModem::JBIG_NONE;
  607.     } else if (valeq(cp, "NO")) {
  608. js = FaxModem::JBIG_NONE;
  609.     } else if (valeq(cp, "FALSE")) {
  610. js = FaxModem::JBIG_NONE;
  611.     } else if (valeq(cp, "SEND")) {
  612. js = FaxModem::JBIG_SEND;
  613.     } else if (valeq(cp, "RECEIVE")) {
  614. js = FaxModem::JBIG_RECV;
  615.     } else if (valeq(cp, "RECV")) {
  616. js = FaxModem::JBIG_RECV;
  617.     } else {
  618. #ifdef HAVE_JBIG
  619. #ifdef HAVE_JBIGTIFF
  620. js = FaxModem::JBIG_FULL;
  621. #else
  622. js = FaxModem::JBIG_SEND;
  623. #endif
  624. #else
  625. #ifdef HAVE_JBIGTIFF
  626. js = FaxModem::JBIG_RECV;
  627. #else
  628. js = FaxModem::JBIG_NONE;
  629. #endif
  630. #endif
  631.     }
  632.     return (js);
  633. }
  634. void
  635. ModemConfig::parseCallID(const char* rbuf, CallID& callid) const
  636. {
  637.     for (size_t i = 0; i < idConfig.length(); i++) {
  638. fxAssert(i < callid.size(), "Miss matched Call ID Size with parsing");
  639. const fxStr& pat = idConfig[i].pattern;
  640. if (pat.length() && strneq(rbuf, pat, pat.length()))
  641.     callid[i].append(rbuf+pat.length());
  642.     }
  643. }
  644. void
  645. ModemConfig::parseDR(const char* cin)
  646. {
  647.     if (strlen(cin) < 3) return;
  648.     char buf[2048];
  649.     strncpy(buf, cin, sizeof (buf));
  650.     char* cp = buf;
  651.     u_int i = 0;
  652.     char* cp1 = cp;
  653.     while (*cp++) {
  654.      if (*cp == ',') {
  655. *cp = '';                     // Nuke the ','
  656. processDRString(cp1, i++);
  657. cp1 = ++cp;
  658. }
  659.     }
  660.     processDRString(cp1, i);
  661.     NoDRings = i + 1;
  662. }
  663. void
  664. ModemConfig::processDRString(char* cp, const u_int i)
  665. {
  666.     if (*cp == 'V')
  667.      distinctiveRings[i].type = ClassModem::CALLTYPE_VOICE;
  668.     else if (*cp == 'F')
  669.      distinctiveRings[i].type = ClassModem::CALLTYPE_FAX;
  670.     else if (*cp == 'D')
  671.      distinctiveRings[i].type = ClassModem::CALLTYPE_DATA;
  672.     while (*cp != '-'){ cp++;}
  673.     *cp = '';
  674.     u_int j = 0;
  675.     int sign = 1;
  676.     char *cp1 = cp += 1;
  677.     while (*cp++) {
  678.      if (*cp == '-') {
  679.     *cp = '';                             // Nuke the '-'
  680.          distinctiveRings[i].cadence[j++] = sign*atoi(cp1);
  681.     sign = -sign;
  682.     cp1 = ++cp;
  683. }
  684.     }
  685.     distinctiveRings[i].cadence[j] =  sign*atoi(cp1);
  686.     double sum = 0;
  687.     for ( u_int k=0; k < 5; ++k ) 
  688.         sum += distinctiveRings[i].cadence[k]*distinctiveRings[i].cadence[k];
  689.     distinctiveRings[i].magsqrd = sum;
  690. }
  691. bool
  692. ModemConfig::setConfigItem(const char* tag, const char* value)
  693. {
  694.     u_int ix;
  695.     if (findTag(tag, (const tags*)atcmds, N(atcmds), ix))
  696. (*this).*atcmds[ix].p = parseATCmd(value);
  697.     else if (findTag(tag, (const tags*)strcmds, N(strcmds), ix))
  698. (*this).*strcmds[ix].p = value;
  699.     else if (findTag(tag, (const tags*)fillorders, N(fillorders), ix))
  700. (*this).*fillorders[ix].p = getFill(value);
  701.     else if (findTag(tag, (const tags*)numbers, N(numbers), ix))
  702. (*this).*numbers[ix].p = atoi(value);
  703.     else if (findTag(tag, (const tags*)booleans, N(booleans), ix))
  704. (*this).*booleans[ix].p = getBoolean(value);
  705.     else if (streq(tag, "modemsetvolumecmd"))
  706. setVolumeCmds(value);
  707.     else if (streq(tag, "modemflowcontrol"))
  708. flowControl = getFlow(value);
  709.     else if (streq(tag, "modemrate"))
  710. maxRate = getRate(value);
  711.     else if (streq(tag, "class1jbigsupport"))
  712.         class1JBIGSupport = getJBIGSupport(value);
  713.     else if (streq(tag, "class2jbigsupport"))
  714.         class2JBIGSupport = getJBIGSupport(value);
  715.     else if (streq(tag, "class1extendedres"))
  716. class1Resolutions = getBoolean(value) ? VR_ALL : (VR_NORMAL | VR_FINE);
  717.     else if (streq(tag, "class1resolutions"))
  718. class1Resolutions = getNumber(value);
  719.     else if (streq(tag, "class1tcfrecvhack") && getBoolean(value))
  720. class1TCFRecvHackCmd = "AT+FRS=1"; // backwards compatibility
  721.     else if (streq(tag, "modemminspeed"))
  722. minSpeed = getSpeed(value);
  723.     else if (streq(tag, "recvdataformat"))
  724. recvDataFormat = getDataFormat(value);
  725.     else if (streq(tag, "rtnhandlingmethod"))
  726.         rtnHandling = getRTNHandling(value);
  727.     else if (streq(tag, "badpagehandlingmethod"))
  728.         badPageHandling = getBadPageHandling(value);
  729.     else if (streq(tag, "class2ecmtype"))
  730. class2ECMType = getECMType(value);
  731.     else if (streq(tag, "distinctiverings"))
  732.      parseDR(value);
  733.     else if (streq(tag, "callidpattern") || streq(tag, "callidanswerlength") || streq(tag, "calliddisplay") 
  734.      || streq(tag, "callidlabel") || streq(tag, "callidrecord") || streq(tag, "callidtype")) {
  735. if (tag[6] == 'p') callidIndex++; // only increment on instances of "Pattern"
  736. if (idConfig.length() < callidIndex+1 && callidIndex != (u_int) -1)
  737.     idConfig.resize(callidIndex+1);
  738. if (tag[6] == 'p') {
  739.     idConfig[callidIndex].answerlength = 0; // we must initialize this
  740.     idConfig[callidIndex].display = false; // we must initialize this
  741.     idConfig[callidIndex].record = true; // we must initialize this
  742.     idConfig[callidIndex].label = ""; // we must initialize this
  743.     idConfig[callidIndex].type = ""; // we must initialize this
  744.     idConfig[callidIndex].pattern = value;
  745.     configTrace("CallID[%d].pattern = "%s"", callidIndex,
  746.     (const char*)idConfig[callidIndex].pattern);
  747. } else {
  748.     if (callidIndex != (u_int) -1) {
  749. switch (tag[6]) {
  750.     case 'a':
  751. idConfig[callidIndex].answerlength = atoi(value);
  752. configTrace("CallID[%d].answerlength = %d", callidIndex,
  753.     idConfig[callidIndex].answerlength);
  754. break;
  755.     case 'd':
  756. idConfig[callidIndex].display = getBoolean(value);
  757. configTrace("CallID[%d].display = %s", callidIndex,
  758.     idConfig[callidIndex].display ? "true" : "false");
  759. break;
  760.     case 'r':
  761. idConfig[callidIndex].record = getBoolean(value);
  762. configTrace("CallID[%d].record = %s", callidIndex,
  763.     idConfig[callidIndex].record ? "true" : "false");
  764. break;
  765.     case 'l':
  766. idConfig[callidIndex].label = value;
  767. configTrace("CallID[%d].label = "%s"", callidIndex,
  768.     (const char*) idConfig[callidIndex].label);
  769. break;
  770.     case 't':
  771. idConfig[callidIndex].type = value;
  772. configTrace("CallID[%d].type = "%s"", callidIndex,
  773.     (const char*) idConfig[callidIndex].type);
  774. break;
  775. }
  776.     } else
  777. configError("No index for Call ID attribute");
  778. }
  779.     } else if (streq(tag, "cidnumber")) {
  780. if (idConfig.length() < CallID::NUMBER+1)
  781.     idConfig.resize(CallID::NUMBER+1);
  782. idConfig[CallID::NUMBER].pattern = value;
  783. idConfig[CallID::NUMBER].answerlength = 0; // we must initialize this
  784. idConfig[CallID::NUMBER].display = false; // we must initialize this
  785. idConfig[CallID::NUMBER].record = true; // we must initialize this
  786. idConfig[CallID::NUMBER].label = ""; // we must initialize this
  787. idConfig[CallID::NUMBER].type = ""; // we must initialize this
  788.     } else if (streq(tag, "cidname")) {
  789. if (idConfig.length() < CallID::NAME+1)
  790.     idConfig.resize(CallID::NAME+1);
  791. idConfig[CallID::NAME].pattern = value;
  792. idConfig[CallID::NAME].answerlength = 0; // we must initialize this
  793. idConfig[CallID::NAME].display = false; // we must initialize this
  794. idConfig[CallID::NAME].record = true; // we must initialize this
  795. idConfig[CallID::NAME].label = ""; // we must initialize this
  796. idConfig[CallID::NAME].type = ""; // we must initialize this
  797.     } else if (streq(tag, "cidnumberanswerlength")) {
  798. if (idConfig.length() < CallID::NUMBER+1)
  799.     idConfig.resize(CallID::NUMBER+1);
  800. idConfig[CallID::NUMBER].answerlength = getNumber(value);
  801.     } else if (streq(tag, "cidnameanswerlength")) {
  802. if (idConfig.length() < CallID::NAME+1)
  803.     idConfig.resize(CallID::NAME+1);
  804. idConfig[CallID::NAME].answerlength = getNumber(value);
  805.     } else
  806. return (false);
  807.     return (true);
  808. }
  809. #undef N
  810. fxIMPLEMENT_ObjArray(IDConfArray, id_config);