Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2236 lines
92 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. class2.c
  5. Abstract:
  6. This is the main source for Class2 specific functions for fax-modem T.30 driver
  7. Author:
  8. Source base was originated by Win95 At Work Fax package.
  9. RafaelL - July 1997 - port to NT
  10. Revision History:
  11. --*/
  12. #include "prep.h"
  13. #include "oemint.h"
  14. #include "efaxcb.h"
  15. #include "tiff.h"
  16. #include "glbproto.h"
  17. #include "t30gl.h"
  18. #include "cl2spec.h"
  19. extern WORD CodeToBPS[16];
  20. extern UWORD rguwClass2Speeds[];
  21. // Here is the table we are using so far for manufacturer specific stuff
  22. MFRSPEC Class2ModemTable[] = {
  23. { "", "Practical Peripherals", "PM14400FXPPM", "", 1, 2, "", FALSE, FALSE, FALSE, FALSE },
  24. { "", "Practical Peripherals", "PM9600FXMT", "", 1, 2, "", FALSE, FALSE, FALSE ,FALSE},
  25. { "", "Everex Systems", "Everfax 24/96E", "", 0, 2, "", FALSE, FALSE, FALSE, FALSE },
  26. { "", "ROCKWELL", "V.32AC", "", 1, 2, "", FALSE, FALSE, FALSE, FALSE },
  27. { "", "ROCKWELL", "RC9624AC", "", 1, 2, "", FALSE, FALSE, FALSE, FALSE },
  28. { "", "Multi-Tech", "MT1432BA", "", 0, 0, "", FALSE, FALSE, FALSE, FALSE },
  29. { "", "SIERRA", "SX196", "", 1, 0, "", TRUE, FALSE, FALSE, FALSE },
  30. { "", "EXAR", "ROCKWELL 144DP", "", 1, 0, "", FALSE, TRUE, FALSE, FALSE },
  31. { "", "ELSA", "MicroLink 2460TL", "", 1, 0, "", FALSE, TRUE, FALSE, FALSE },
  32. { "", "GVC", "ROCKWELL 144DP", "", 1, 0, "", FALSE, TRUE, TRUE , FALSE }, // Intel144Ex
  33. { "", "ADC", "SL144V32", "", 1, 0, "", FALSE, TRUE, FALSE, FALSE },
  34. { "", "UMC", "", "", 1, 0, "", FALSE, TRUE, FALSE ,FALSE},
  35. { "", "NetComm", "", "", 1, 0, "", FALSE, TRUE, FALSE, FALSE },
  36. { "", "HALCYON", "Bit Blitzer", "", 0, 0, "", FALSE, FALSE, FALSE, FALSE },
  37. { "", "", "", "", 1, 0, "", FALSE, FALSE, FALSE, FALSE }
  38. };
  39. void
  40. Class2Init(
  41. PThrdGlbl pTG
  42. )
  43. {
  44. pTG->lpCmdTab = 0;
  45. pTG->Class2bDLEETX[0] = DLE;
  46. pTG->Class2bDLEETX[1] = ETX;
  47. pTG->Class2bDLEETX[2] = 0;
  48. sprintf( pTG->cbszFDT, "AT+FDT\r" );
  49. sprintf( pTG->cbszINITIAL_FDT, "AT+FDT=%%1d,%%1d,%%1d,%%1d\r" );
  50. sprintf( pTG->cbszFDR, "AT+FDR\r" );
  51. sprintf( pTG->cbszFPTS, "AT+FPTS=%%d\r" );
  52. sprintf( pTG->cbszFCR, "AT+FCR=1\r" );
  53. sprintf( pTG->cbszFCQ, "AT+FCQ=0\r" );
  54. sprintf( pTG->cbszFBUG, "AT+FBUG=0\r" );
  55. sprintf( pTG->cbszSET_FBOR, "AT+FBOR=%%d\r" );
  56. // DCC - set High Res, Huffman, no ECM/BFT, default all others.
  57. sprintf( pTG->cbszFDCC_ALL, "AT+FDCC=1,%%d,,,0,0,0,\r" );
  58. sprintf( pTG->cbszFDCC_RECV_ALL, "AT+FDCC=1,%%d,2,2,0,0,0,\r" );
  59. sprintf( pTG->cbszFDIS_RECV_ALL, "AT+FDIS=1,%%d,2,2,0,0,0,\r" );
  60. sprintf( pTG->cbszFDCC_RES, "AT+FDCC=1\r" );
  61. sprintf( pTG->cbszFDCC_BAUD, "AT+FDCC=1,%%d\r" );
  62. sprintf( pTG->cbszFDIS_BAUD, "AT+FDIS=1,%%d\r" );
  63. sprintf( pTG->cbszFDIS_IS, "AT+FDIS?\r" );
  64. sprintf( pTG->cbszFDIS_NOQ_IS, "AT+FDIS\r" );
  65. sprintf( pTG->cbszFDCC_IS, "AT+FDCC?\r" );
  66. sprintf( pTG->cbszFDIS_STRING, "+FDIS" );
  67. sprintf( pTG->cbszFDIS, "AT+FDIS=%%1d,%%1d,%%1d,%%1d,%%1d,0,0,0\r" );
  68. sprintf( pTG->cbszZERO, "0" );
  69. sprintf( pTG->cbszONE, "1" );
  70. sprintf( pTG->cbszQUERY_S1, "ATS1?\r" );
  71. sprintf( pTG->cbszRING, "RING" );
  72. sprintf( pTG->cbszCLASS2_ATI, "ATI\r" );
  73. sprintf( pTG->cbszCLASS2_FMFR, "AT+FMFR?\r" );
  74. sprintf( pTG->cbszCLASS2_FMDL, "AT+FMDL?\r" );
  75. sprintf( pTG->cbszFDT_CONNECT, "CONNECT" );
  76. sprintf( pTG->cbszFDT_CNTL_Q, "" );
  77. sprintf( pTG->cbszFCON, "+FCON" );
  78. sprintf( pTG->cbszGO_CLASS2, "AT+FCLASS=2\r" );
  79. sprintf( pTG->cbszFLID, "AT+FLID=\"%%s\"\r" );
  80. sprintf( pTG->cbszENDPAGE, "AT+FET=0\r" );
  81. sprintf( pTG->cbszENDMESSAGE, "AT+FET=2\r" );
  82. sprintf( pTG->cbszCLASS2_QUERY_CLASS,"AT+FCLASS=?\r" );
  83. sprintf( pTG->cbszCLASS2_GO_CLASS0, "AT+FCLASS=0\r" );
  84. sprintf( pTG->cbszCLASS2_ATTEN, "AT\r" );
  85. sprintf( pTG->cbszATA, "ATA\r" );
  86. sprintf( pTG->cbszCLASS2_NODIALTONE, "NO DIALTONE");
  87. sprintf( pTG->cbszCLASS2_HANGUP, "ATH0\r" );
  88. sprintf( pTG->cbszCLASS2_CALLDONE, "ATS0=0\r" );
  89. sprintf( pTG->cbszCLASS2_ABORT, "AT+FK\r" );
  90. sprintf( pTG->cbszCLASS2_DIAL, "ATD%%c %%s\r" );
  91. sprintf( pTG->cbszCLASS2_NODIALTONE, "NO DIALTONE" );
  92. sprintf( pTG->cbszCLASS2_BUSY, "BUSY" );
  93. sprintf( pTG->cbszCLASS2_NOANSWER, "NO ANSWER" );
  94. sprintf( pTG->cbszCLASS2_OK, "OK" );
  95. sprintf( pTG->cbszCLASS2_FHNG, "+FHNG" );
  96. sprintf( pTG->cbszCLASS2_ERROR, "ERROR" );
  97. Class2SetProtParams(pTG, &pTG->Inst.ProtParams);
  98. }
  99. BOOL
  100. T30Cl2Tx(
  101. PThrdGlbl pTG,
  102. LPSTR szPhone
  103. )
  104. // If lpszSection is NON-NULL, we will override our internal CurrentMSPEC
  105. // structure based on the settings in the specified section.
  106. //
  107. {
  108. LPSTR lpszSection = pTG->FComModem.rgchKey;
  109. USHORT uRet1, uRet2;
  110. BYTE bBuf[200],
  111. bTempBuf[200+RESPONSE_BUF_SIZE];
  112. LPBYTE lpbyte;
  113. UWORD Encoding, Res, PageWidth, PageLength, uwLen, uwRet;
  114. BYTE bIDBuf[200+max(MAXTOTALIDLEN,20)+4];
  115. CHAR szTSI[max(MAXTOTALIDLEN,20)+4];
  116. BOOL fBaudChanged;
  117. BOOL RetCode;
  118. uRet2 = 0;
  119. if(!(pTG->lpCmdTab = iModemGetCmdTabPtr(pTG)))
  120. {
  121. (MyDebugPrint (pTG, LOG_ALL, "<<ERROR>> Class2Caller: iModemGetCmdTabPtr failed.\n\r"));
  122. uRet1 = T30_CALLFAIL;
  123. pTG->fFatalErrorWasSignaled = 1;
  124. SignalStatusChange(pTG, FS_FATAL_ERROR);
  125. RetCode = FALSE;
  126. goto done;
  127. }
  128. // first get SEND_CAPS if possible. If using PSI (IFAX/Winpad) then we
  129. // can't make callback this on the Sender. Only on Receiver! Otherwise
  130. // we deadlock & hang in PSI
  131. #ifdef PSI
  132. if(!Class2GetBC(pTG, BC_NONE)) // Set it to some defaults!
  133. #else
  134. if(!Class2GetBC(pTG, SEND_CAPS)) // get send caps
  135. #endif
  136. {
  137. uRet1 = T30_CALLFAIL;
  138. pTG->fFatalErrorWasSignaled = 1;
  139. SignalStatusChange(pTG, FS_FATAL_ERROR);
  140. RetCode = FALSE;
  141. goto done;
  142. }
  143. // Go to Class2
  144. if(!iModemGoClass(pTG, 2))
  145. {
  146. (MyDebugPrint (pTG, LOG_ALL, "Class2Caller: Failed to Go to Class 2 \n\r"));
  147. uRet1 = T30_CALLFAIL;
  148. pTG->fFatalErrorWasSignaled = 1;
  149. SignalStatusChange(pTG, FS_FATAL_ERROR);
  150. RetCode = FALSE;
  151. goto done;
  152. }
  153. // Begin by checking for manufacturer and ATI code.
  154. // Look this up against the modem specific table we
  155. // have and set up the send strings needed for
  156. // this modem.
  157. if(!Class2GetModemMaker(pTG ))
  158. {
  159. (MyDebugPrint (pTG, LOG_ALL, "Call to GetModemMaker failed\n\r"));
  160. // Ignore failure!!!
  161. }
  162. // set manufacturer specific strings
  163. Class2SetMFRSpecific(pTG, lpszSection);
  164. // Get the capabilities of the software. I am only using this
  165. // right now for the TSI field (below where I send +FLID).
  166. // Really, this should also be used instead of the hardcoded DIS
  167. // values below.
  168. // ALL COMMANDS LOOK FOR MULTILINE RESPONSES WHILE MODEM IS ONHOOK.
  169. // A "RING" COULD APPEAR AT ANY TIME!
  170. _fmemset((LPB)szTSI, 0, strlen(szTSI));
  171. Class2SetDIS_DCSParams(pTG, SEND_CAPS, (LPUWORD)&Encoding, (LPUWORD)&Res,
  172. (LPUWORD)&PageWidth, (LPUWORD)&PageLength, (LPSTR) szTSI);
  173. bIDBuf[0] = '\0';
  174. uwLen = (UWORD)wsprintf(bIDBuf, pTG->cbszFLID, (LPSTR)szTSI);
  175. if(!Class2iModemDialog(pTG, bIDBuf, uwLen,
  176. LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  177. pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  178. {
  179. (MyDebugPrint (pTG, LOG_ALL, "Local ID failed\n\r"));
  180. // ignore failure
  181. }
  182. // // Turn off ECM - don't do for sierra type modems!
  183. // if (!pTG->CurrentMFRSpec.bIsSierra)
  184. // if(!Class2iModemDialog(pTG->cbszFECM, sizeof(pTG->cbszFECM)-1,
  185. // LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  186. // pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  187. // {
  188. // (MyDebugPrint (pTG, LOG_ALL, "FECM failed\n\r"));
  189. // // Ignore ECM failure!!!
  190. // }
  191. // Turn off Bug mode
  192. if(!Class2iModemDialog(pTG, pTG->cbszFBUG, (UWORD) (strlen(pTG->cbszFBUG) ),
  193. LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  194. pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  195. {
  196. (MyDebugPrint (pTG, LOG_ALL, "FBUG failed\n\r"));
  197. // Ignore FBUG failure!!!
  198. }
  199. // Find out what the default DIS is
  200. if (!pTG->CurrentMFRSpec.bIsExar)
  201. {
  202. if(!(uwRet=Class2iModemDialog(pTG, pTG->cbszFDIS_IS, (UWORD) (strlen(pTG->cbszFDIS_IS) ),
  203. LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  204. pTG->cbszCLASS2_ERROR, (C2PSTR) NULL)))
  205. {
  206. (MyDebugPrint (pTG, LOG_ALL, "FDIS failed\n\r"));
  207. // ignore
  208. }
  209. }
  210. // See if the reply was ERROR or timeout, if so try a different command
  211. // Exar modems, for example, don't take AT+FDIS?
  212. if ( ( uwRet == 2) || (uwRet == 0) || pTG->CurrentMFRSpec.bIsExar)
  213. {
  214. // FDIS did not work!!! Try FDCC?
  215. if(!(uwRet=Class2iModemDialog(pTG, pTG->cbszFDCC_IS,
  216. (UWORD) (strlen(pTG->cbszFDCC_IS) ), LOCALCOMMAND_TIMEOUT, TRUE, 0,
  217. pTG->cbszCLASS2_OK, pTG->cbszCLASS2_ERROR, (C2PSTR) NULL)))
  218. {
  219. // Ignore
  220. }
  221. if ( (uwRet == 2) || (uwRet == 0 ) )
  222. {
  223. // The FDCC failed - maybe it is an Exar that likes FDIS?
  224. // try that
  225. if(!(uwRet=Class2iModemDialog(pTG, pTG->cbszFDIS_IS,
  226. (UWORD) (strlen(pTG->cbszFDIS_IS) ), LOCALCOMMAND_TIMEOUT, TRUE, 0,
  227. pTG->cbszCLASS2_OK, pTG->cbszCLASS2_ERROR, (C2PSTR) NULL)))
  228. {
  229. //ignore
  230. }
  231. // Maybe it is the Class 2 modem referred to in
  232. // Elliot bug #1238 that wants FDIS without a
  233. // question mark
  234. if ( (uwRet == 2) || (uwRet == 0 ) )
  235. {
  236. if(!(uwRet=Class2iModemDialog(pTG, pTG->cbszFDIS_NOQ_IS,
  237. (UWORD) (strlen(pTG->cbszFDIS_NOQ_IS) ), LOCALCOMMAND_TIMEOUT, TRUE, 0,
  238. pTG->cbszCLASS2_OK, (C2PSTR) NULL)))
  239. {
  240. // No FDIS, FDCC worked - quit!
  241. (MyDebugPrint (pTG, LOG_ALL, "<<ERROR>> No FDIS? or FDCC? worked\n\r"));
  242. uRet1 = T30_CALLFAIL;
  243. pTG->fFatalErrorWasSignaled = 1;
  244. SignalStatusChange(pTG, FS_FATAL_ERROR);
  245. RetCode = FALSE;
  246. goto done;
  247. }
  248. }
  249. }
  250. // If the first character in the reply before a number
  251. // is a ',', insert a '1' for normal & fine res (Exar hack)
  252. for (lpbyte = pTG->lpbResponseBuf2; *lpbyte != '\0'; lpbyte++)
  253. {
  254. if (*lpbyte == ',')
  255. {
  256. // found a leading comma
  257. bTempBuf[0] = '\0';
  258. _fstrcpy((LPSTR)bBuf, (LPSTR)pTG->cbszONE);
  259. wsprintf((LPSTR)bTempBuf, "%s%s",(LPSTR)bBuf,
  260. lpbyte);
  261. _fstrcpy(lpbyte, bTempBuf);
  262. (MyDebugPrint (pTG, LOG_ALL, "Leading comma in DCC string =\n\r", (LPSTR)&pTG->lpbResponseBuf2));
  263. }
  264. if ( (*lpbyte >= '0') && (*lpbyte <= '9') ) break;
  265. }
  266. }
  267. // If the repsonse was just a number string without "+FDIS" in front
  268. // of it, add the +FDIS. Some modem reply with it, some do not. The
  269. // general parsing algorithm used below in Class2ResponseAction needs
  270. // to know the command that the numbers refer to.
  271. if ( pTG->lpbResponseBuf2[0] != '\0' &&
  272. (Class2_fstrstr((LPSTR)pTG->lpbResponseBuf2, (LPSTR)pTG->cbszFDIS_STRING)==NULL))
  273. {
  274. // did not get the FDIS in the response!
  275. bTempBuf[0] = '\0';
  276. _fstrcpy((LPSTR)bBuf, (LPSTR)pTG->cbszFDIS_STRING);
  277. wsprintf((LPSTR)bTempBuf, "%s: %s",(LPSTR)bBuf,
  278. (LPSTR)pTG->lpbResponseBuf2);
  279. _fstrcpy(pTG->lpbResponseBuf2, bTempBuf);
  280. }
  281. (MyDebugPrint (pTG, LOG_ALL, "\n\rReceived %s from FDIS\r\n", (LPSTR)(&(pTG->lpbResponseBuf2))));
  282. // Process default DIS to see if we have to send a DCC to change
  283. // it. Some modems react badly to just sending a DCC with ",,,"
  284. // so we can't rely on the modem keeping DIS parameters unchanged
  285. // after a DCC like that. We'll use the FDISResponse routine to load
  286. // the default DIS values into a PCB structure
  287. if ( Class2ResponseAction(pTG, (LPPCB) &pTG->DISPcb) == FALSE )
  288. {
  289. (MyDebugPrint (pTG, LOG_ALL, "Failed to process FDIS Response\n\r"));
  290. uRet1 = T30_CALLFAIL;
  291. pTG->fFatalErrorWasSignaled = 1;
  292. SignalStatusChange(pTG, FS_FATAL_ERROR);
  293. RetCode = FALSE;
  294. goto done;
  295. }
  296. (MyDebugPrint (pTG, LOG_ALL, "pTG->DISPcb baud value is %d\n\r", pTG->DISPcb.Baud));
  297. fBaudChanged = FALSE;
  298. // See if we have to change the baud rate to a lower value.
  299. // This only happens if the user set an ini string constraining
  300. // the high end speed or if the user turned off V.17 for sending
  301. // Check the V.17 inhibit and lower baud if necessary
  302. if ( (pTG->DISPcb.Baud > 3) && (!pTG->ProtParams2.fEnableV17Send) )
  303. {
  304. (MyDebugPrint (pTG, LOG_ALL, "Lowering baud from %d for V.17 inihibit\n\r", CodeToBPS[pTG->DISPcb.Baud]));
  305. pTG->DISPcb.Baud = 3; //9600 won't use V.17
  306. fBaudChanged = TRUE;
  307. }
  308. // - commented out 3/6/95 by JosephJ (this code was never checked in -- it
  309. // fixed one modem and didn't fix another.
  310. // else if (pTG->DISPcb.Baud == 5)
  311. // {
  312. // // Several 14.4K modems require us to explicitly set
  313. // // +FDCC=1,5 or ,5 to work, else they send at 2400!
  314. // // So force the specification of +FDCC
  315. // (MyDebugPrint (pTG, LOG_ALL, "Faking fBaudChanged for 14.4K modems\n\r"));
  316. // fBaudChanged=TRUE;
  317. // }
  318. // Now see if the high end baud rate has been constrained
  319. if ( (pTG->ProtParams2.HighestSendSpeed != 0) &&
  320. (CodeToBPS[pTG->DISPcb.Baud] > (WORD)pTG->ProtParams2.HighestSendSpeed))
  321. {
  322. (MyDebugPrint (pTG, LOG_ALL, "Have to lower baud from %d to %d\n\r", CodeToBPS[pTG->DISPcb.Baud], pTG->ProtParams2.HighestSendSpeed));
  323. fBaudChanged = TRUE;
  324. switch (pTG->ProtParams2.HighestSendSpeed)
  325. {
  326. case 2400:
  327. pTG->DISPcb.Baud = 0;
  328. break;
  329. case 4800:
  330. pTG->DISPcb.Baud = 1;
  331. break;
  332. case 7200:
  333. pTG->DISPcb.Baud = 2;
  334. break;
  335. case 9600:
  336. pTG->DISPcb.Baud = 3;
  337. break;
  338. case 12000:
  339. pTG->DISPcb.Baud = 4;
  340. break;
  341. default:
  342. (MyDebugPrint (pTG, LOG_ALL, "Bad HighestSpeed\n\r"));
  343. uRet1 = T30_CALLFAIL;
  344. pTG->fFatalErrorWasSignaled = 1;
  345. SignalStatusChange(pTG, FS_FATAL_ERROR);
  346. RetCode = FALSE;
  347. goto done;
  348. break;
  349. }
  350. }
  351. // Now, look and see if any of the values in the DIS are "bad"
  352. // That is, make sure we can send high res and we are not
  353. // claiming that we are sending MR or MMR. Also, see if we changed
  354. // the baud rate.
  355. if ((pTG->DISPcb.Resolution & AWRES_mm080_077) && ( pTG->DISPcb.Encoding == MH_DATA)
  356. && (!fBaudChanged) )
  357. {
  358. //Do nothing - leave DIS alone!
  359. (MyDebugPrint (pTG, LOG_ALL, "no need to change DIS\n\r"));
  360. }
  361. else
  362. {
  363. // Send DCC command to the modem to set it up
  364. // Do the minimum necessary - only set resoultion if possible
  365. // (Again, this is because some modems don't like FDCC).
  366. if ( (pTG->DISPcb.Encoding == MH_DATA) && (!fBaudChanged) )
  367. {
  368. if(!Class2iModemDialog(pTG, pTG->cbszFDCC_RES, (UWORD) (strlen(pTG->cbszFDCC_RES) ),
  369. LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  370. (C2PSTR) NULL))
  371. {
  372. uRet1 = T30_CALLFAIL;
  373. pTG->fFatalErrorWasSignaled = 1;
  374. SignalStatusChange(pTG, FS_FATAL_ERROR);
  375. RetCode = FALSE;
  376. goto done;
  377. }
  378. }
  379. else if ( (pTG->DISPcb.Encoding == MH_DATA) && (fBaudChanged) )
  380. {
  381. // Changed the baud rate, but Encoding is OK.
  382. uwLen=(UWORD)wsprintf((LPSTR)bBuf, pTG->cbszFDCC_BAUD, pTG->DISPcb.Baud);
  383. if(!Class2iModemDialog(pTG, bBuf, uwLen,
  384. LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  385. (C2PSTR) NULL))
  386. {
  387. uRet1 = T30_CALLFAIL;
  388. pTG->fFatalErrorWasSignaled = 1;
  389. SignalStatusChange(pTG, FS_FATAL_ERROR);
  390. RetCode = FALSE;
  391. goto done;
  392. }
  393. }
  394. else // the encoding format has changed
  395. {
  396. uwLen=(UWORD)wsprintf((LPSTR)bBuf, pTG->cbszFDCC_ALL, pTG->DISPcb.Baud);
  397. if(!Class2iModemDialog(pTG, bBuf, uwLen,
  398. LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  399. (C2PSTR) NULL))
  400. {
  401. uRet1 = T30_CALLFAIL;
  402. pTG->fFatalErrorWasSignaled = 1;
  403. SignalStatusChange(pTG, FS_FATAL_ERROR);
  404. RetCode = FALSE;
  405. goto done;
  406. }
  407. }
  408. }
  409. // Do BOR based on the value from the modem table set in
  410. // Class2SetMFRSpecific
  411. uwLen = (UWORD)wsprintf(bBuf, pTG->cbszSET_FBOR, pTG->CurrentMFRSpec.iSendBOR);
  412. if(!Class2iModemDialog(pTG, bBuf, uwLen, LOCALCOMMAND_TIMEOUT, TRUE,
  413. 0, pTG->cbszCLASS2_OK, pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  414. {
  415. (MyDebugPrint (pTG, LOG_ALL, "FBOR failed\n\r"));
  416. // Ignore BOR failure!!!
  417. }
  418. // Dial the number
  419. // have to call hangup on every path out of here
  420. // after Dial is called. If Dial fails, it calls Hangup
  421. // if it succeeds we have to call Hangup when we're done
  422. SignalStatusChange(pTG, FS_DIALING);
  423. if((uRet2 = Class2Dial(pTG, szPhone)) != CONNECT_OK)
  424. {
  425. uRet1 = T30_DIALFAIL;
  426. if (! pTG->fFatalErrorWasSignaled) {
  427. pTG->fFatalErrorWasSignaled = 1;
  428. SignalStatusChange(pTG, FS_FATAL_ERROR);
  429. }
  430. RetCode = FALSE;
  431. goto done;
  432. }
  433. ICommGotAnswer(pTG );
  434. // we should be using the sender msg here but that says Training
  435. // at speed=xxxx etc which we don't know, so we just use the
  436. // Recvr message which just says "negotiating"
  437. ICommStatus(pTG, T30STATR_TRAIN, 0, 0, 0);
  438. // Send the data
  439. uRet1 = (USHORT)Class2Send(pTG );
  440. if ( uRet1 == T30_CALLDONE)
  441. {
  442. (MyDebugPrint (pTG, LOG_ALL, "******* DONE WITH CALL, ALL OK\r\n"));
  443. ICommStatus(pTG, T30STATS_SUCCESS, 0, 0, 0);
  444. // have to call hangup on every path out of here
  445. // we have to call Hangup here
  446. Class2ModemHangup(pTG );
  447. SignalStatusChange(pTG, FS_COMPLETED);
  448. RetCode = TRUE;
  449. }
  450. else
  451. {
  452. (MyDebugPrint (pTG, LOG_ALL, "******* DONE WITH CALL, **** FAILED *****\r\n"));
  453. ICommStatus(pTG, T30STATS_FAIL, 0, 0, 0);
  454. // Make sure Modem is in OK state
  455. FComOutFilterClose(pTG );
  456. FComXon(pTG, FALSE);
  457. // have to call hangup on every path out of here
  458. // Class2ModemABort calls Hangup
  459. Class2ModemAbort(pTG );
  460. if (! pTG->fFatalErrorWasSignaled) {
  461. pTG->fFatalErrorWasSignaled = 1;
  462. SignalStatusChange(pTG, FS_FATAL_ERROR);
  463. }
  464. RetCode = FALSE;
  465. }
  466. BG_CHK(uRet1==T30_CALLDONE || uRet1==T30_CALLFAIL);
  467. uRet2 = 0;
  468. done:
  469. BG_CHK((uRet1 & 0xFF) == uRet1);
  470. BG_CHK((uRet2 & 0xFF) == uRet2);
  471. return RetCode;
  472. }
  473. BOOL Class2Send(PThrdGlbl pTG)
  474. {
  475. LPBUFFER lpbf;
  476. SWORD swRet;
  477. ULONG lTotalLen=0;
  478. PCB Pcb;
  479. USHORT uTimeout=30000, PagesSent;
  480. BOOL err_status, fAllPagesOK = TRUE;
  481. BCwithTEXT bc;
  482. UWORD Encoding, Res, PageWidth, PageLength, uwLen;
  483. BYTE bFDISBuf[200];
  484. CHAR szTSI[max(MAXTOTALIDLEN,20)+4];
  485. BYTE bNull = 0;
  486. DWORD TiffConvertThreadId;
  487. /*
  488. * We have just dialed... Now we have to look for the FDIS response from
  489. * the modem. It will be followed by an OK - hunt for the OK.
  490. */
  491. if(!Class2iModemDialog(pTG, NULL, 0, STARTSENDMODE_TIMEOUT, TRUE, 0,
  492. pTG->cbszCLASS2_OK, (C2PSTR) NULL))
  493. {
  494. err_status = T30_CALLFAIL;
  495. return err_status;
  496. }
  497. // The response will be in pTG->lpbResponseBuf2 - this is loaded in
  498. // Class2iModemDialog.
  499. // (MyDebugPrint (pTG, LOG_ALL, "Received %s\r", (LPSTR)(&(pTG->lpbResponseBuf2))));
  500. // Parse through the received strings, looking for the DIS, CSI,
  501. // NSF
  502. if ( Class2ResponseAction(pTG, (LPPCB) &Pcb) == FALSE )
  503. {
  504. (MyDebugPrint (pTG, LOG_ALL, "Failed to process ATD Response\n\r"));
  505. err_status = T30_CALLFAIL;
  506. return err_status;
  507. }
  508. //Now that pcb is set up, call ICommReceiveCaps to tell icomfile
  509. Class2InitBC(pTG, (LPBC)&bc, sizeof(bc), RECV_CAPS);
  510. Class2PCBtoBC(pTG, (LPBC)&bc, sizeof(bc), &Pcb);
  511. // Class2 modems do their own negotiation & we need to stay in sync
  512. // Otherwise, we might send MR data while the modem sends a DCS
  513. // saying it is MH. This happens a lot with Exar modems because
  514. // they dont accept an FDIS= command during the call.
  515. // FIX: On all Class2 sends force remote caps to always be MH
  516. // Then in efaxrun we will always negotiate MH & encode MH
  517. // We are relying on the fact that (a) it seems that all/most
  518. // Class2 modems negotiate MH (b) Hopefully ALL Exar ones
  519. // negotiate MH and (c) We will override all non-Exar modem's
  520. // intrinsic negotiation by sending an AT+FDIS= just before the FDT
  521. // Also (d) This change makes our behaviour match Snowball exactly
  522. // so we will work no better or worse than it :-)
  523. bc.Fax.Encoding = MH_DATA;
  524. if( ICommRecvCaps(pTG, (LPBC)&bc) == FALSE )
  525. {
  526. (MyDebugPrint (pTG, LOG_ALL, "Failed return from ICommRecvCaps.\r\n"));
  527. err_status = T30_CALLFAIL;
  528. return err_status;
  529. }
  530. // now get the SEND_PARAMS
  531. if(!Class2GetBC(pTG, SEND_PARAMS)) // sleep until we get it
  532. {
  533. err_status = T30_CALLFAIL;
  534. return err_status;
  535. }
  536. #ifdef FILET30
  537. // Send the raw capabilities string - most values
  538. // will be null, since CAS does not tell us things like
  539. // DIS, NSF, etc. But, we can put in the CSI.
  540. ICommRawCaps(pTG, (LPBYTE) &bNull, (LPBYTE) &bNull, 0, NULL, 0);
  541. #endif
  542. ICommSetSendMode(pTG, FALSE, MY_BIGBUF_SIZE, MY_BIGBUF_ACTUALSIZE-4, FALSE);
  543. // Turn off flow control.
  544. FComXon(pTG, FALSE);
  545. // The Send params were set during the call to Class2GetBC
  546. // We'll use these to set the ID (for the TSI) and the DCS params
  547. // Send the FDT and get back the DCS. The FDT must be followed by
  548. // CONNECT and a ^Q (XON)
  549. // The FDT string must have the correct resolution and encoding
  550. // for this session. FDT=Encoding, Res, width, length
  551. // Encoding 0=MH, 1=MR,2=uncompressed,3=MMR
  552. // Res 0=200x100 (normal), 1=200x200 (fine)
  553. // PageWidth 0=1728pixels/215mm,1=2048/255,2=2432/303,
  554. // 3=1216/151,4=864/107
  555. // PageLength 0=A4,1=B4,2=unlimited
  556. Class2SetDIS_DCSParams(pTG, SEND_PARAMS, (LPUWORD)&Encoding,
  557. (LPUWORD)&Res, (LPUWORD)&PageWidth, (LPUWORD)&PageLength,
  558. (LPSTR) szTSI);
  559. //
  560. // Current Win95 version of Class2 TX is limited to MH only.
  561. // While not changing this, we will at least allow MR selection in future.
  562. //
  563. if (!pTG->fTiffThreadCreated) {
  564. if (Encoding) {
  565. pTG->TiffConvertThreadParams.tiffCompression = TIFF_COMPRESSION_MR;
  566. }
  567. else {
  568. pTG->TiffConvertThreadParams.tiffCompression = TIFF_COMPRESSION_MH;
  569. }
  570. if (Res) {
  571. pTG->TiffConvertThreadParams.HiRes = 1;
  572. }
  573. else {
  574. pTG->TiffConvertThreadParams.HiRes = 0;
  575. // use LoRes TIFF file prepared by FaxSvc
  576. // pTG->lpwFileName[ wcslen(pTG->lpwFileName) - 1] = (unsigned short) ('$');
  577. }
  578. _fmemcpy (pTG->TiffConvertThreadParams.lpszLineID, pTG->lpszPermanentLineID, 8);
  579. pTG->TiffConvertThreadParams.lpszLineID[8] = 0;
  580. (MyDebugPrint(pTG, LOG_ALL, "Creating TIFF helper thread \r\n"));
  581. pTG->hThread = CreateThread(
  582. NULL,
  583. 0,
  584. (LPTHREAD_START_ROUTINE) TiffConvertThreadSafe,
  585. (LPVOID) pTG,
  586. 0,
  587. &TiffConvertThreadId
  588. );
  589. if (!pTG->hThread) {
  590. (MyDebugPrint(pTG, LOG_ERR, "<<ERROR>> TiffConvertThread create FAILED\r\n"));
  591. err_status = T30_CALLFAIL;
  592. return err_status;
  593. }
  594. pTG->fTiffThreadCreated = 1;
  595. pTG->AckTerminate = 0;
  596. pTG->fOkToResetAbortReqEvent = 0;
  597. if ( (pTG->RecoveryIndex >=0 ) && (pTG->RecoveryIndex < MAX_T30_CONNECT) ) {
  598. T30Recovery[pTG->RecoveryIndex].TiffThreadId = TiffConvertThreadId;
  599. T30Recovery[pTG->RecoveryIndex].CkSum = ComputeCheckSum(
  600. (LPDWORD) &T30Recovery[pTG->RecoveryIndex].fAvail,
  601. sizeof ( T30_RECOVERY_GLOB ) / sizeof (DWORD) - 1 );
  602. }
  603. }
  604. // Even modems that take FDT=x,x,x,x don't seem to really do it
  605. // right. So, for now, just send FDIS followed by FDT except for
  606. // the EXAR modems!!
  607. if (pTG->CurrentMFRSpec.bIsExar)
  608. {
  609. if(!Class2iModemDialog(pTG, pTG->cbszFDT, (UWORD) (strlen(pTG->cbszFDT) ),
  610. STARTSENDMODE_TIMEOUT, TRUE, 0,
  611. pTG->cbszFDT_CONNECT,(C2PSTR) NULL))
  612. {
  613. (MyDebugPrint (pTG, LOG_ALL, "Failed get response from initial FDT!!\r\n"));
  614. err_status = T30_CALLFAIL;
  615. return err_status;
  616. }
  617. // (MyDebugPrint (pTG, LOG_ALL, "FDT Received %s\r\n", (LPSTR)(&(pTG->lpbResponseBuf2))));
  618. }
  619. else
  620. {
  621. uwLen = (WORD)wsprintf(bFDISBuf, pTG->cbszFDIS, Res,
  622. min(Pcb.Baud, pTG->DISPcb.Baud), PageWidth, PageLength, Encoding);
  623. if(!Class2iModemDialog(pTG, bFDISBuf, uwLen, LOCALCOMMAND_TIMEOUT,
  624. TRUE, 0, pTG->cbszCLASS2_OK, pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  625. {
  626. (MyDebugPrint (pTG, LOG_ALL, "Failed get response from FDIS!!\r\n"));
  627. // Ignore it -we are going to send what we have!
  628. }
  629. if(!Class2iModemDialog(pTG, pTG->cbszFDT, (UWORD) (strlen(pTG->cbszFDT) ),
  630. STARTSENDMODE_TIMEOUT, TRUE, 0,
  631. pTG->cbszFDT_CONNECT,(C2PSTR) NULL))
  632. {
  633. (MyDebugPrint (pTG, LOG_ALL, "FDT Received %s\r\n",(LPSTR)(&(pTG->lpbResponseBuf2))));
  634. (MyDebugPrint (pTG, LOG_ALL, "FDT to start first PAGE Failed!\n\r"));
  635. err_status = T30_CALLFAIL;
  636. return err_status;
  637. }
  638. (MyDebugPrint (pTG, LOG_ALL, "FDT Received %s\r\n", (LPSTR)(&(pTG->lpbResponseBuf2))));
  639. }
  640. if (pTG->CurrentMFRSpec.fSkipCtrlQ)
  641. {
  642. (MyDebugPrint (pTG, LOG_ALL, "WARNING!! Skipping cntl-q - sending immedaitely after CONNECT\n\r"));
  643. }
  644. // Get the  from the COMM driver
  645. else if(!FComGetOneChar(pTG, 0x11))
  646. {
  647. (MyDebugPrint (pTG, LOG_ALL, "Couldn't Get cntl q - we'll go ahead anyway\n\r"));
  648. }
  649. // Turn on flow control.
  650. FComXon(pTG, TRUE);
  651. // Search through Response for the DCS frame - need it so set
  652. // the correct zero stuffing
  653. if ( Class2ResponseAction(pTG, (LPPCB) &Pcb) == FALSE )
  654. {
  655. (MyDebugPrint (pTG, LOG_ALL, "Failed to process FDT Response\n\r"));
  656. err_status = T30_CALLFAIL;
  657. return err_status;
  658. }
  659. // Got a response - see if baud rate is OK
  660. (MyDebugPrint (pTG, LOG_ALL, "Negotiated Baud Rate = %d, lower limit is %d\n\r", Pcb.Baud, pTG->ProtParams2.LowestSendSpeed));
  661. if (CodeToBPS[Pcb.Baud] < (WORD)pTG->ProtParams2.LowestSendSpeed)
  662. {
  663. (MyDebugPrint (pTG, LOG_ALL, "Aborting due to too low baud rate!\n\r"));
  664. err_status = T30_CALLFAIL;
  665. return err_status;
  666. }
  667. // Use values obtained from the DCS frame to set zero stuffing.
  668. // (These were obtained by call to Class2ResponseAction above).
  669. // Zero stuffing is a function of minimum scan time (determined
  670. // by resolution and the returned scan minimum) and baud.
  671. // Fixed the Hack--added a Baud field
  672. // Init must be BEFORE SetStuffZero!
  673. FComOutFilterInit(pTG );
  674. FComSetStuffZERO(pTG, Class2MinScanToBytesPerLine(pTG, Pcb.MinScan, (BYTE) Pcb.Baud, Pcb.Resolution));
  675. PagesSent = 0;
  676. err_status = T30_CALLDONE;
  677. while ((swRet=ICommGetSendBuf(pTG, &lpbf, SEND_STARTPAGE)) == 0)
  678. {
  679. (MyDebugPrint (pTG, LOG_ALL, "IN MULTIPAGE WHILE LOOP. Pages Sent = %d\n\r", PagesSent));
  680. //// faxTlog(("SENDING Reams of Page Data.....\r\n"));
  681. lTotalLen = 0;
  682. FComOverlappedIO(pTG, TRUE); // TRUE
  683. while ((swRet=ICommGetSendBuf(pTG, &lpbf, SEND_SEQ)) == 0)
  684. {
  685. BG_CHK(lpbf && lpbf->wLengthData > 0);
  686. lTotalLen += lpbf->wLengthData;
  687. (MyDebugPrint (pTG, LOG_ALL, "TOTAL LENGTH: %ld\r\n", lTotalLen));
  688. if(!(Class2ModemSendMem(pTG, lpbf->lpbBegData,
  689. lpbf->wLengthData) & (MyFreeBuf(pTG, lpbf))))
  690. {
  691. (MyDebugPrint (pTG, LOG_ALL, "Class2ModemSendBuf Failed\r\n"));
  692. err_status = T30_CALLFAIL;
  693. FComOverlappedIO(pTG, FALSE);
  694. return err_status;
  695. }
  696. if (pTG->fAbort)
  697. {
  698. (MyDebugPrint (pTG, LOG_ALL, "Abort during Send loop\r\n"));
  699. pTG->fAbort = FALSE;
  700. err_status = T30_CALLFAIL;
  701. FComOverlappedIO(pTG, FALSE);
  702. return err_status;
  703. }
  704. } // end of SEND_SEQ while
  705. FComOverlappedIO(pTG, FALSE);
  706. (MyDebugPrint (pTG, LOG_ALL, "OUT OF WHILE SEND_SEQ LOOP. \r\n"));
  707. (MyDebugPrint (pTG, LOG_ALL, "TOTAL LENGTH: %ld\r\n", lTotalLen));
  708. // Terminate the Page with DLE-ETX
  709. if(!FComDirectAsyncWrite(pTG, pTG->Class2bDLEETX, 2))
  710. {
  711. (MyDebugPrint (pTG, LOG_ALL, "Failed to terminate page with DLE-ETX\n\r"));
  712. err_status = T30_CALLFAIL;
  713. return err_status;
  714. }
  715. if(!Class2ModemDrain(pTG ))
  716. {
  717. (MyDebugPrint (pTG, LOG_ALL, "Failed to drain\n\r"));
  718. err_status = T30_CALLFAIL;
  719. return err_status;
  720. }
  721. //See if more pages to send...
  722. if ( ICommNextSend(pTG) == NEXTSEND_MPS )
  723. {
  724. // We are about to send a second or more page. Terminate the
  725. // last page with FET=0, signalling a new one to come
  726. if(!Class2iModemDialog(pTG, pTG->cbszENDPAGE, (UWORD) (strlen(pTG->cbszENDPAGE) ),
  727. STARTSENDMODE_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK, (C2PSTR)NULL))
  728. {
  729. (MyDebugPrint (pTG, LOG_ALL, "END PAGE Processing Failed!\n\r"));
  730. err_status = T30_CALLFAIL;
  731. return err_status;
  732. }
  733. // Acknowledge that we sent the page
  734. // Parse the FPTS response and see if the page is good or bad.
  735. // Keep track of any bad pages in fAllPagesOK
  736. if (!ParseFPTS_SendAck(pTG ))
  737. fAllPagesOK = FALSE;
  738. PagesSent++;
  739. // Now, Send the FDT to start the next page (this was done for
  740. // the first page before entering the multipage loop).
  741. if(!Class2iModemDialog(pTG, pTG->cbszFDT, (UWORD) (strlen(pTG->cbszFDT) ),
  742. STARTSENDMODE_TIMEOUT, TRUE, 0,
  743. pTG->cbszFDT_CONNECT,(C2PSTR) NULL))
  744. {
  745. (MyDebugPrint (pTG, LOG_ALL, "FDT to start next PAGE Failed!\n\r"));
  746. err_status = T30_CALLFAIL;
  747. return err_status;
  748. }
  749. // Get the  from the COMM driver
  750. if(!FComGetOneChar(pTG, 0x11))
  751. {
  752. (MyDebugPrint (pTG, LOG_ALL, "Couldn't Get cntl q - we'll go ahead anyway\n\r"));
  753. }
  754. // Turn on flow control.
  755. FComXon(pTG, TRUE);
  756. } //if we do not have another page, do the else...
  757. else break; // All done sending pages...
  758. if ( err_status == T30_CALLFAIL) break;
  759. } //End of multipage while
  760. (MyDebugPrint (pTG, LOG_ALL, "OUT OF WHILE MULTIPAGE LOOP. ABOUT TO SEND FINAL.\r\n"));
  761. //
  762. // Purge input COM queue to purge all OKs
  763. //
  764. FComFlushInput(pTG);
  765. // Send end of message sequence
  766. if(!Class2iModemDialog(pTG, pTG->cbszENDMESSAGE, (UWORD) (strlen(pTG->cbszENDMESSAGE) ),
  767. STARTSENDMODE_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK, (C2PSTR)NULL))
  768. {
  769. (MyDebugPrint (pTG, LOG_ALL, "End message failed\n\r"));
  770. err_status = T30_CALLFAIL;
  771. return err_status;
  772. }
  773. // Acknowledge that we sent the page
  774. // Parse the FPTS response and see if the page is good or bad.
  775. if (!ParseFPTS_SendAck(pTG )) fAllPagesOK = FALSE;
  776. PagesSent++;
  777. FComOutFilterClose(pTG );
  778. FComXon(pTG, FALSE);
  779. // If *any* page failed to send correctly, the call failed!
  780. if (!fAllPagesOK) err_status = T30_CALLFAIL;
  781. return err_status;
  782. }
  783. /**************************************************************
  784. Receive specific routines start here
  785. ***************************************************************/
  786. BOOL T30Cl2Rx (PThrdGlbl pTG)
  787. // If lpszSection is NON-NULL, we will override our internal CurrentMSPEC
  788. // structure based on the settings in the specified section.
  789. {
  790. LPSTR lpszSection = pTG->FComModem.rgchKey;
  791. USHORT uRet1, uRet2;
  792. BYTE bBuf[200],
  793. bTempBuf[200+RESPONSE_BUF_SIZE];
  794. UWORD uwLen, uwRet;
  795. UWORD Encoding, Res, PageWidth, PageLength;
  796. BYTE bIDBuf[200+max(MAXTOTALIDLEN,20)+4];
  797. CHAR szCSI[max(MAXTOTALIDLEN,20)+4];
  798. LPBYTE lpbyte;
  799. BOOL fBaudChanged;
  800. BOOL RetCode;
  801. (MyDebugPrint (pTG, LOG_ALL, "Entering Class2 Callee\n\r"));
  802. uRet2 = 0;
  803. if(!(pTG->lpCmdTab = iModemGetCmdTabPtr(pTG )))
  804. {
  805. (MyDebugPrint (pTG, LOG_ALL, "<<ERROR>> Class2Callee: iModemGetCmdTabPtr failed.\n\r"));
  806. uRet1 = T30_CALLFAIL;
  807. pTG->fFatalErrorWasSignaled = 1;
  808. SignalStatusChange(pTG, FS_FATAL_ERROR);
  809. RetCode = FALSE;
  810. goto done;
  811. }
  812. // first get SEND_CAPS
  813. if(!Class2GetBC(pTG, SEND_CAPS)) // sleep until we get it
  814. {
  815. uRet1 = T30_CALLFAIL;
  816. pTG->fFatalErrorWasSignaled = 1;
  817. SignalStatusChange(pTG, FS_FATAL_ERROR);
  818. RetCode = FALSE;
  819. goto done;
  820. }
  821. // Go to Class2
  822. // Elliot Bug#3421 -- incoming RING sometimes clobbers AT+FCLASS=1/2 cmd.
  823. if(pTG->lpCmdTab->dwFlags & fMDMSP_ANS_GOCLASS_TWICE) iModemGoClass(pTG, 2);
  824. if(!iModemGoClass(pTG, 2))
  825. {
  826. (MyDebugPrint (pTG, LOG_ALL, "Class2Callee: Failed to Go to Class 2 \n\r"));
  827. uRet1 = T30_CALLFAIL;
  828. pTG->fFatalErrorWasSignaled = 1;
  829. SignalStatusChange(pTG, FS_FATAL_ERROR);
  830. RetCode = FALSE;
  831. goto done;
  832. }
  833. // Begin by checking for manufacturer and ATI code.
  834. // Look this up against the modem specific table we
  835. // have and set up the receive strings needed for
  836. // this modem.
  837. if(!Class2GetModemMaker(pTG ))
  838. {
  839. (MyDebugPrint (pTG, LOG_ALL, "Call to GetModemMaker failed\n\r"));
  840. // Ignore failure!!!
  841. }
  842. // set manufacturer specific strings
  843. Class2SetMFRSpecific(pTG, lpszSection);
  844. // Get the capabilities of the software. I am only using this
  845. // right now for the CSI field (below where I send +FLID).
  846. // Really, this should also be used instead of the hardcoded DIS
  847. // values below.
  848. // ALL COMMANDS LOOK FOR MULTILINE RESPONSES WHILE MODEM IS ONHOOK.
  849. // A "RING" COULD APPEAR AT ANY TIME!
  850. _fmemset((LPB)szCSI, 0, sizeof(szCSI));
  851. Class2SetDIS_DCSParams(pTG, SEND_CAPS, (LPUWORD)&Encoding, (LPUWORD)&Res,
  852. (LPUWORD)&PageWidth, (LPUWORD)&PageLength, (LPSTR) szCSI);
  853. // Find out what the default DIS is
  854. if (!pTG->CurrentMFRSpec.bIsExar)
  855. {
  856. if(!(uwRet=Class2iModemDialog(pTG, pTG->cbszFDIS_IS, (UWORD) (strlen(pTG->cbszFDIS_IS) ),
  857. LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  858. pTG->cbszCLASS2_ERROR, (C2PSTR) NULL)))
  859. {
  860. (MyDebugPrint (pTG, LOG_ALL, "FDIS? failed\n\r"));
  861. // ignore
  862. }
  863. }
  864. // See if the reply was ERROR or timeout, if so try a different command
  865. // Exar modems, for example, don't take AT+FDIS?
  866. if ( ( uwRet == 2) || (uwRet == 0) || pTG->CurrentMFRSpec.bIsExar)
  867. {
  868. // FDIS did not work!!! Try FDCC?
  869. if(!(uwRet=Class2iModemDialog(pTG, pTG->cbszFDCC_IS,
  870. (UWORD) (strlen(pTG->cbszFDCC_IS) ), LOCALCOMMAND_TIMEOUT, TRUE, 0,
  871. pTG->cbszCLASS2_OK, pTG->cbszCLASS2_ERROR, (C2PSTR) NULL)))
  872. {
  873. // Ignore
  874. }
  875. if ( (uwRet == 2) || (uwRet == 0 ) )
  876. {
  877. // The FDCC failed - maybe it is an Exar that likes FDIS?
  878. // try that
  879. if(!(uwRet=Class2iModemDialog(pTG, pTG->cbszFDIS_IS,
  880. (UWORD) (strlen(pTG->cbszFDIS_IS) ), LOCALCOMMAND_TIMEOUT, TRUE, 0,
  881. pTG->cbszCLASS2_OK, pTG->cbszCLASS2_ERROR, (C2PSTR) NULL)))
  882. {
  883. //ignore
  884. }
  885. // Maybe it is the Class 2 modem referred to in
  886. // Elliot bug #1238 that wants FDIS without a
  887. // question mark
  888. if ( (uwRet == 2) || (uwRet == 0 ) )
  889. {
  890. if(!(uwRet=Class2iModemDialog(pTG, pTG->cbszFDIS_NOQ_IS,
  891. (UWORD) (strlen(pTG->cbszFDIS_NOQ_IS) ), LOCALCOMMAND_TIMEOUT, TRUE, 0,
  892. pTG->cbszCLASS2_OK, (C2PSTR) NULL)))
  893. {
  894. // No FDIS, FDCC worked - quit!
  895. (MyDebugPrint (pTG, LOG_ALL, "<<ERROR>> No FDIS? or FDCC? worked\n\r"));
  896. uRet1 = T30_CALLFAIL;
  897. pTG->fFatalErrorWasSignaled = 1;
  898. SignalStatusChange(pTG, FS_FATAL_ERROR);
  899. RetCode = FALSE;
  900. goto done;
  901. }
  902. }
  903. }
  904. // If the first character in the reply before a number
  905. // is a ',', insert a '1' for normal & fine res (Exar hack)
  906. for (lpbyte = pTG->lpbResponseBuf2; *lpbyte != '\0'; lpbyte++)
  907. {
  908. if (*lpbyte == ',')
  909. {
  910. // found a leading comma
  911. bTempBuf[0] = '\0';
  912. _fstrcpy((LPSTR)bBuf, (LPSTR)pTG->cbszONE);
  913. wsprintf((LPSTR)bTempBuf, "%s%s",(LPSTR)bBuf,
  914. lpbyte);
  915. _fstrcpy(lpbyte, bTempBuf);
  916. (MyDebugPrint (pTG, LOG_ALL, "Leading comma in DCC string =\n\r", (LPSTR)&pTG->lpbResponseBuf2));
  917. }
  918. if ( (*lpbyte >= '0') && (*lpbyte <= '9') ) break;
  919. }
  920. }
  921. // If the repsonse was just a number string without "+FDIS" in front
  922. // of it, add the +FDIS. Some modem reply with it, some do not. The
  923. // general parsing algorithm used below in Class2ResponseAction needs
  924. // to know the command that the numbers refer to.
  925. if ( pTG->lpbResponseBuf2[0] != '\0' &&
  926. (Class2_fstrstr( (LPSTR)pTG->lpbResponseBuf2, (LPSTR)pTG->cbszFDIS_STRING)==NULL))
  927. {
  928. // did not get the FDIS in the response!
  929. bTempBuf[0] = '\0';
  930. _fstrcpy((LPSTR)bBuf, (LPSTR)pTG->cbszFDIS_STRING);
  931. wsprintf((LPSTR)bTempBuf, "%s: %s",(LPSTR)bBuf,
  932. (LPSTR)pTG->lpbResponseBuf2);
  933. _fstrcpy(pTG->lpbResponseBuf2, bTempBuf);
  934. }
  935. (MyDebugPrint (pTG, LOG_ALL, "Received %s from FDIS?\r", (LPSTR)(&(pTG->lpbResponseBuf2))));
  936. // Process default DIS to see if we have to send a DCC to change
  937. // it. Some modems react badly to just sending a DCC with ",,,"
  938. // so we can't rely on the modem keeping DIS parameters unchanged
  939. // after a DCC like that. We'll use the FDISResponse routine to load
  940. // the default DIS values into a PCB structure
  941. if ( Class2ResponseAction(pTG, (LPPCB) &pTG->DISPcb) == FALSE )
  942. {
  943. (MyDebugPrint (pTG, LOG_ALL, "Failed to process FDIS Response\n\r"));
  944. uRet1 = T30_CALLFAIL;
  945. pTG->fFatalErrorWasSignaled = 1;
  946. SignalStatusChange(pTG, FS_FATAL_ERROR);
  947. RetCode = FALSE;
  948. goto done;
  949. }
  950. fBaudChanged = FALSE;
  951. // See if we have to change the baud rate to a lower value.
  952. // This only happens if the user set an ini string inhibiting
  953. // V.17 receive
  954. if ( (pTG->DISPcb.Baud > 3) && (!pTG->ProtParams2.fEnableV17Recv) )
  955. {
  956. (MyDebugPrint (pTG, LOG_ALL, "Lowering baud from %d for V.17 receive inihibit\n\r", CodeToBPS[pTG->DISPcb.Baud]));
  957. pTG->DISPcb.Baud = 3; //9600 won't use V.17
  958. fBaudChanged = TRUE;
  959. }
  960. // - commented out 3/6/95 by JosephJ (this code was never checked in -- it
  961. // fixed one modem and didn't fix another.
  962. // else if (pTG->DISPcb.Baud == 5)
  963. // {
  964. // // Several 14.4K modems require us to explicitly set
  965. // // +FDCC=1,5 or ,5 to work, else they send at 2400!
  966. // // So force the specification of +FDCC
  967. // (MyDebugPrint (pTG, LOG_ALL, "Faking fBaudChanged for 14.4K modems\n\r"));
  968. // fBaudChanged=TRUE;
  969. // }
  970. // Now, look and see if any of the values in the DIS are "bad"
  971. // That is, make sure we can receive high res and we are not
  972. // claiming that we are capable of MR or MMR. Also, see if we changed
  973. // the baud rate. Also make sure we can receive wide pages.
  974. if ((pTG->DISPcb.Resolution & AWRES_mm080_077) && ( pTG->DISPcb.Encoding == MH_DATA)
  975. && (!fBaudChanged)
  976. && (pTG->DISPcb.PageLength == 2) && (pTG->DISPcb.PageWidth == 2) )
  977. {
  978. //Do nothing - leave DIS alone!
  979. (MyDebugPrint (pTG, LOG_ALL, "no need to change DIS\n\r"));
  980. }
  981. else
  982. {
  983. // Send DCC command to the modem to set it up
  984. // Do the minimum necessary - only set resoultion if possible
  985. // (Again, this is because some modems don't like FDCC).
  986. if ( (pTG->DISPcb.Encoding == MH_DATA) && (!fBaudChanged)
  987. && (pTG->DISPcb.PageLength == 2) && (pTG->DISPcb.PageWidth == 2) )
  988. {
  989. if(!Class2iModemDialog(pTG, pTG->cbszFDCC_RES, (UWORD) (strlen(pTG->cbszFDCC_RES) ),
  990. LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  991. (C2PSTR) NULL))
  992. {
  993. //Ignore it
  994. }
  995. }
  996. else if ( (pTG->DISPcb.Encoding == MH_DATA) && (fBaudChanged)
  997. && (pTG->DISPcb.PageLength == 2) && (pTG->DISPcb.PageWidth == 2) )
  998. {
  999. // Changed the baud rate, but Encoding is OK.
  1000. uwLen=(USHORT)wsprintf((LPSTR)bBuf, pTG->cbszFDCC_BAUD, pTG->DISPcb.Baud);
  1001. if(!Class2iModemDialog(pTG, bBuf, uwLen,
  1002. LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  1003. (C2PSTR) NULL))
  1004. {
  1005. //Ignore it
  1006. }
  1007. }
  1008. else // the encoding format has changed or page size is bad
  1009. {
  1010. uwLen=(USHORT)wsprintf((LPSTR)bBuf, pTG->cbszFDCC_RECV_ALL, pTG->DISPcb.Baud);
  1011. if(!(uwRet=Class2iModemDialog(pTG, bBuf, uwLen,
  1012. LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  1013. pTG->cbszCLASS2_ERROR, (C2PSTR) NULL)))
  1014. {
  1015. // ignore it.
  1016. }
  1017. // If the FDCC failed, try FDIS.
  1018. if ( (uwRet == 0) || (uwRet == 2) )
  1019. {
  1020. uwLen=(USHORT)wsprintf((LPSTR)bBuf, pTG->cbszFDIS_RECV_ALL, pTG->DISPcb.Baud);
  1021. if(!Class2iModemDialog(pTG, bBuf, uwLen,
  1022. LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  1023. pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  1024. {
  1025. // ignore it.
  1026. }
  1027. // if the above failed, try just setting the baud
  1028. // rate and resolution with FDCC.
  1029. if ( (uwRet == 0) || (uwRet == 2) )
  1030. {
  1031. uwLen=(USHORT)wsprintf((LPSTR)bBuf, pTG->cbszFDCC_BAUD, pTG->DISPcb.Baud);
  1032. if(!(uwRet=Class2iModemDialog(pTG, bBuf, uwLen,
  1033. LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  1034. pTG->cbszCLASS2_ERROR, (C2PSTR) NULL)))
  1035. {
  1036. // Ignore it
  1037. }
  1038. }
  1039. // if the above failed, try just setting the baud
  1040. // rate and resolution with FDIS.
  1041. if ( (uwRet == 0) || (uwRet == 2) )
  1042. {
  1043. uwLen=(USHORT)wsprintf((LPSTR)bBuf, pTG->cbszFDIS_BAUD, pTG->DISPcb.Baud);
  1044. if(!(uwRet=Class2iModemDialog(pTG, bBuf, uwLen,
  1045. LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  1046. pTG->cbszCLASS2_ERROR, (C2PSTR) NULL)))
  1047. {
  1048. // Ignore it
  1049. }
  1050. }
  1051. }
  1052. }
  1053. }
  1054. // Enable Reception
  1055. if(!Class2iModemDialog(pTG, pTG->cbszFCR, (UWORD) (strlen(pTG->cbszFCR) ),
  1056. ANS_LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  1057. pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  1058. {
  1059. (MyDebugPrint (pTG, LOG_ALL, "FCR failed\n\r"));
  1060. // ignore failure
  1061. }
  1062. // // Turn off ECM - don't do for sierra type modems!
  1063. // if (!pTG->CurrentMFRSpec.bIsSierra)
  1064. // if(!Class2iModemDialog(pTG->cbszFECM, sizeof(pTG->cbszFECM)-1,
  1065. // ANS_LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  1066. // pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  1067. // {
  1068. // (MyDebugPrint (pTG, LOG_ALL, "FECM failed\n\r"));
  1069. // // Ignore ECM failure!!!
  1070. // }
  1071. // Turn off Copy Quality Checking - also skip for Sierra type modems
  1072. if (!pTG->CurrentMFRSpec.bIsSierra)
  1073. if(!Class2iModemDialog(pTG, pTG->cbszFCQ, (UWORD) (strlen(pTG->cbszFCQ) ),
  1074. ANS_LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  1075. pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  1076. {
  1077. (MyDebugPrint (pTG, LOG_ALL, "FCQ failed\n\r"));
  1078. // Ignore CQ failure!!!
  1079. }
  1080. // Turn off Bug mode
  1081. if(!Class2iModemDialog(pTG, pTG->cbszFBUG, (UWORD) (strlen(pTG->cbszFBUG) ),
  1082. ANS_LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  1083. pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  1084. {
  1085. (MyDebugPrint (pTG, LOG_ALL, "FBUG failed\n\r"));
  1086. // Ignore FBUG failure!!!
  1087. }
  1088. // Do BOR based on the value from the modem table set in
  1089. // Class2SetMFRSpecific
  1090. bBuf[0] = '\0';
  1091. {
  1092. UINT uBOR = pTG->CurrentMFRSpec.iReceiveBOR;
  1093. if (pTG->CurrentMFRSpec.fSWFBOR && uBOR==1)
  1094. {
  1095. (MyDebugPrint (pTG, LOG_ALL, "<<WARNING>> SWFBOR Enabled. Using AT+FBOR=0 instead of AT+FBOR=1\r\n"));
  1096. uBOR=0;
  1097. }
  1098. uwLen = (USHORT)wsprintf(bBuf, pTG->cbszSET_FBOR, uBOR);
  1099. }
  1100. if(!Class2iModemDialog(pTG, bBuf, uwLen, ANS_LOCALCOMMAND_TIMEOUT, TRUE,
  1101. 0, pTG->cbszCLASS2_OK, pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  1102. {
  1103. (MyDebugPrint (pTG, LOG_ALL, "FBOR failed\n\r"));
  1104. // Ignore BOR failure!!!
  1105. }
  1106. // Set the local ID - need ID from above to do this.
  1107. bIDBuf[0] = '\0';
  1108. uwLen = (USHORT)wsprintf(bIDBuf, pTG->cbszFLID, (LPSTR)szCSI);
  1109. if(!Class2iModemDialog(pTG, bIDBuf, uwLen,
  1110. ANS_LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  1111. pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  1112. {
  1113. (MyDebugPrint (pTG, LOG_ALL, "Local ID failed\n\r"));
  1114. // ignore failure
  1115. }
  1116. // Answer the phone
  1117. // have to call hangup on every path out of here
  1118. // after Answer is called. If Answer fails, it calls Hangup.
  1119. // if it succeeds we have to call Hangup when we're done
  1120. SignalStatusChange(pTG, FS_ANSWERED);
  1121. if((uRet2 = Class2Answer(pTG, FALSE)) != CONNECT_OK)
  1122. {
  1123. (MyDebugPrint (pTG, LOG_ALL, "Answer failed\n\r"));
  1124. uRet1 = T30_CALLFAIL;
  1125. pTG->fFatalErrorWasSignaled = 1;
  1126. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1127. RetCode = FALSE;
  1128. goto done;
  1129. }
  1130. (MyDebugPrint (pTG, LOG_ALL, "Done with Class2 Answer - succeeded!!\n\r"));
  1131. ICommStatus(pTG, T30STATR_TRAIN, 0, 0, 0);
  1132. // Receive the data
  1133. uRet1 = (USHORT)Class2Receive(pTG );
  1134. if ( uRet1 == T30_CALLDONE)
  1135. {
  1136. (MyDebugPrint (pTG, LOG_ALL, "******* DONE WITH CALL, ALL OK\r\n"));
  1137. ICommStatus(pTG, T30STATR_SUCCESS, 0, 0, 0);
  1138. // have to call hangup on every path out of here
  1139. // we have to call Hangup here
  1140. Class2ModemHangup(pTG );
  1141. SignalStatusChange(pTG, FS_COMPLETED);
  1142. RetCode = TRUE;
  1143. }
  1144. else
  1145. {
  1146. (MyDebugPrint (pTG, LOG_ALL, "******* DONE WITH CALL, **** FAILED *****\r\n"));
  1147. ICommStatus(pTG, T30STATR_FAIL, 0, 0, 0);
  1148. // Make sure modem is in an OK state!
  1149. FComXon(pTG, FALSE);
  1150. // have to call hangup on every path out of here
  1151. // Abort calls Hangup
  1152. Class2ModemAbort(pTG );
  1153. pTG->fFatalErrorWasSignaled = 1;
  1154. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1155. RetCode = FALSE;
  1156. }
  1157. BG_CHK(uRet1==T30_CALLDONE || uRet1==T30_CALLFAIL);
  1158. uRet2 = 0;
  1159. done:
  1160. BG_CHK((uRet1 & 0xFF) == uRet1);
  1161. BG_CHK((uRet2 & 0xFF) == uRet2);
  1162. return RetCode;
  1163. }
  1164. BOOL Class2Receive(PThrdGlbl pTG)
  1165. {
  1166. LPBUFFER lpbf;
  1167. SWORD swRet;
  1168. UWORD uwLen;
  1169. ULONG lTotalLen=0;
  1170. PCB Pcb;
  1171. USHORT uTimeout=30000, uRet, PagesReceived, uFPTSarg;
  1172. BOOL err_status;
  1173. BCwithTEXT bc;
  1174. BYTE bBuf[200];
  1175. DWORD tiffCompression;
  1176. LPSTR lpsTemp;
  1177. DWORD HiRes;
  1178. // FComCriticalNeg(TRUE);
  1179. //// faxTlog(("\r\n\r\n\r\n\r\n\r\n======================= Entering Class 2 Receive*** ==============================\r\n\r\n\r\n\r\n"));
  1180. /*
  1181. * We have just answered!
  1182. */
  1183. // The repsonse to the ATA command is in the global variable
  1184. // pTG->lpbResponseBuf2.
  1185. if ( Class2ResponseAction(pTG, (LPPCB) &Pcb) == FALSE )
  1186. {
  1187. (MyDebugPrint (pTG, LOG_ALL, "Failed to process ATA Response\n\r"));
  1188. err_status = T30_CALLFAIL;
  1189. return err_status;
  1190. }
  1191. //Now that pcb is set up, call ICommReceiveParams to tell icomfile
  1192. Class2InitBC(pTG, (LPBC)&bc, sizeof(bc), RECV_PARAMS);
  1193. Class2PCBtoBC(pTG, (LPBC)&bc, sizeof(bc), &Pcb);
  1194. if( ICommRecvParams(pTG, (LPBC)&bc) == FALSE )
  1195. {
  1196. (MyDebugPrint (pTG, LOG_ALL, "Failed return from ICommRecvParams.\r\n"));
  1197. err_status = T30_CALLFAIL;
  1198. return err_status;
  1199. }
  1200. //
  1201. // once per RX - create TIFF file as soon as we know the compression / resolution.
  1202. //
  1203. pTG->Encoding = Pcb.Encoding;
  1204. pTG->Resolution = Pcb.Resolution;
  1205. if (Pcb.Encoding == MR_DATA) {
  1206. tiffCompression = TIFF_COMPRESSION_MR;
  1207. }
  1208. else {
  1209. tiffCompression = TIFF_COMPRESSION_MH;
  1210. }
  1211. if (Pcb.Resolution & (AWRES_mm080_077 | AWRES_200_200) ) {
  1212. HiRes = 1;
  1213. }
  1214. else {
  1215. HiRes = 0;
  1216. }
  1217. if ( !pTG->fTiffOpenOrCreated) {
  1218. //
  1219. // top 32bits of 64bit handle are guaranteed to be zero
  1220. //
  1221. pTG->Inst.hfile = PtrToUlong( TiffCreateW ( pTG->lpwFileName,
  1222. tiffCompression,
  1223. 1728,
  1224. FILLORDER_LSB2MSB,
  1225. HiRes
  1226. ) );
  1227. if (! (pTG->Inst.hfile)) {
  1228. lpsTemp = UnicodeStringToAnsiString(pTG->lpwFileName);
  1229. MyDebugPrint(pTG, LOG_ERR, "ERROR:Can't create tiff file %s compr=%d \n",
  1230. lpsTemp,
  1231. tiffCompression);
  1232. MemFree(lpsTemp);
  1233. err_status = T30_CALLFAIL;
  1234. return err_status;
  1235. }
  1236. pTG->fTiffOpenOrCreated = 1;
  1237. lpsTemp = UnicodeStringToAnsiString(pTG->lpwFileName);
  1238. MyDebugPrint(pTG, LOG_ALL, "Created tiff file %s compr=%d HiRes=%d \n",
  1239. lpsTemp, tiffCompression, HiRes);
  1240. MemFree(lpsTemp);
  1241. }
  1242. // we set buffer sizes and recv mode (ECM/non-ECM) here
  1243. ICommSetRecvMode(pTG, FALSE); // always non-ECM?
  1244. // **** Apparently, we don't want flow control on, so we'll turn
  1245. // it off. Is this true???? If I turn it on, fcom.c fails a
  1246. // debug check in filterreadbuf.
  1247. FComXon(pTG, FALSE);
  1248. // Send the FDR. The FDR must be responded to by a CONNECT.
  1249. if(!Class2iModemDialog(pTG, pTG->cbszFDR, (UWORD) (strlen(pTG->cbszFDR) ),
  1250. STARTSENDMODE_TIMEOUT, TRUE, 0,
  1251. pTG->cbszFDT_CONNECT,(C2PSTR) NULL))
  1252. {
  1253. (MyDebugPrint (pTG, LOG_ALL, "Failed get response from initial FDR!!\r\n"));
  1254. err_status = T30_CALLFAIL;
  1255. return err_status;
  1256. }
  1257. (MyDebugPrint (pTG, LOG_ALL, "FDR Received %s\r", (LPSTR)(&(pTG->lpbResponseBuf2))));
  1258. // Might have to search through FDR response, but I doubt it.
  1259. // Now we need to send a DC2 (0x12) to tell the modem it is OK
  1260. // to give us data.
  1261. // Some modems use ^Q instead of ^R - The correct value was written
  1262. // into the DC@ string in Class2Callee where we checked for
  1263. // manufacturer
  1264. FComDirectSyncWriteFast(pTG, pTG->CurrentMFRSpec.szDC2, 1);
  1265. // Now we can receive the data and give it to the icomfile routine
  1266. PagesReceived = 0;
  1267. err_status = T30_CALLDONE;
  1268. while ((swRet=(SWORD)ICommPutRecvBuf(pTG, NULL, RECV_STARTPAGE)) == TRUE)
  1269. {
  1270. (MyDebugPrint (pTG, LOG_ALL, "IN MULTIPAGE WHILE LOOP. Pages Received = %d\n\r", PagesReceived));
  1271. //// faxTlog(("Receiving Reams of Page Data.....\r\n"));
  1272. // The READ_TIMEOUT is used to timeout calls to ReadBuf() either in the
  1273. #define READ_TIMEOUT 15000
  1274. lTotalLen = 0;
  1275. do
  1276. {
  1277. (MyDebugPrint (pTG, LOG_ALL, "In receiving a page loop\n\r"));
  1278. uRet=Class2ModemRecvBuf(pTG, &lpbf, READ_TIMEOUT);
  1279. (MyDebugPrint(pTG, LOG_ALL, "Class2ModemRecvBuf: uRet=%x\n\r", uRet ));
  1280. if(lpbf)
  1281. {
  1282. lTotalLen += lpbf->wLengthData;
  1283. (MyDebugPrint (pTG, LOG_ALL, "In lpbf if. length = %ld, Total Length %ld\n\r", lpbf->wLengthData, lTotalLen));
  1284. if(!ICommPutRecvBuf(pTG, lpbf, RECV_SEQ))
  1285. {
  1286. (MyDebugPrint (pTG, LOG_ALL, "Bad return - PutRecvBuf in page\r\n"));
  1287. err_status=T30_CALLFAIL;
  1288. return err_status;
  1289. }
  1290. lpbf = 0;
  1291. }
  1292. }
  1293. while(uRet == RECV_OK);
  1294. (MyDebugPrint (pTG, LOG_ALL, "Out of RECV_SEQ do loop\n\r"));
  1295. if(uRet == RECV_EOF)
  1296. {
  1297. (MyDebugPrint (pTG, LOG_ALL, "Got EOF from RecvBuf\n\r"));
  1298. // FComCriticalNeg(TRUE);
  1299. // RSL needed interface to TIFF thread
  1300. pTG->fLastReadBlock = 1;
  1301. ICommPutRecvBuf(pTG, NULL, RECV_FLUSH);
  1302. }
  1303. else
  1304. {
  1305. // Timeout from ModemRecvBuf
  1306. (MyDebugPrint (pTG, LOG_ALL, "ModemRecvBuf Timeout or Error=%d\r\n", uRet));
  1307. err_status = T30_CALLFAIL;
  1308. return err_status;
  1309. }
  1310. //// faxTlog(pTG, ("Page Recv Done.....len=(%ld, 0x%08x)\r\n", lTotalLen, lTotalLen));
  1311. PagesReceived++;
  1312. Class2GetRecvPageAck(pTG );
  1313. // Set the FPTS parameter based on the global pTG->fRecvPageOK variable.
  1314. // This variable was set during the call to Class2GetRecvPageAck above.
  1315. // The quality of the page was checked during that call.
  1316. // This command will cause an the next FDR command to send either
  1317. // "MCF" or "RTN".
  1318. if (pTG->fRecvPageOK) uFPTSarg = 1; // 1 indicates a good page
  1319. else uFPTSarg = 2; // 2 indicates a bad page, retrain requested.
  1320. // See if more pages to receive by parsing the FDR response...
  1321. // After the DLEETX was received by Class2ModemRecvBuf, the
  1322. // FPTS and FET response should be coming from the modem, terminated
  1323. // by an OK. Let's go read that!
  1324. if(!Class2iModemDialog(pTG, NULL, 0,
  1325. STARTSENDMODE_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK, (C2PSTR)NULL))
  1326. {
  1327. (MyDebugPrint (pTG, LOG_ALL, "END PAGE Processing Failed!\n\r"));
  1328. err_status = T30_CALLFAIL;
  1329. return err_status;
  1330. }
  1331. (MyDebugPrint (pTG, LOG_ALL, "EOP Received %s\r", (LPSTR)(&(pTG->lpbResponseBuf2))));
  1332. // Process the response and see if more pages are coming
  1333. if (Class2EndPageResponseAction(pTG ) == MORE_PAGES)
  1334. {
  1335. ICommPutRecvBuf(pTG, NULL, RECV_ENDPAGE);
  1336. // Send the FPTS - don't do this for Exar modems!
  1337. if (!pTG->CurrentMFRSpec.bIsExar)
  1338. {
  1339. uwLen = (UWORD)wsprintf(bBuf, pTG->cbszFPTS, uFPTSarg);
  1340. if(!Class2iModemDialog(pTG, bBuf, uwLen,
  1341. LOCALCOMMAND_TIMEOUT, TRUE, 0,
  1342. pTG->cbszCLASS2_OK, pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  1343. {
  1344. (MyDebugPrint (pTG, LOG_ALL, "FPTS= failed\n\r"));
  1345. // Ignore FPTS failure!!!
  1346. }
  1347. }
  1348. // Now, Send the FDR to start the next page (this was done for
  1349. // the first page before entering the multipage loop).
  1350. if(!Class2iModemDialog(pTG, pTG->cbszFDR, (UWORD) (strlen(pTG->cbszFDR) ),
  1351. STARTSENDMODE_TIMEOUT, TRUE, 0,
  1352. pTG->cbszFDT_CONNECT,(C2PSTR) NULL))
  1353. {
  1354. (MyDebugPrint (pTG, LOG_ALL, "FDR to start next PAGE Failed!\n\r"));
  1355. err_status = T30_CALLFAIL;
  1356. return err_status;
  1357. }
  1358. // Now send the correct DC2 string set in Class2Callee
  1359. // (DC2 is standard, some use ^q instead)
  1360. FComDirectSyncWriteFast(pTG, pTG->CurrentMFRSpec.szDC2, 1);
  1361. } //if we do not have another page, do the else...
  1362. else break; // All done receiving pages...
  1363. } //End of multipage while
  1364. (MyDebugPrint (pTG, LOG_ALL, "OUT OF WHILE MULTIPAGE LOOP. ABOUT TO SEND FINAL FDR.\r\n"));
  1365. //RSL
  1366. ICommPutRecvBuf(pTG, NULL, RECV_ENDDOC);
  1367. // Send end of message sequence
  1368. // Send the last FPTS - do we really need to do this???
  1369. if (!pTG->CurrentMFRSpec.bIsExar)
  1370. {
  1371. uwLen = (UWORD)wsprintf(bBuf, pTG->cbszFPTS, uFPTSarg);
  1372. if(!Class2iModemDialog(pTG, bBuf, uwLen, LOCALCOMMAND_TIMEOUT, TRUE,
  1373. 0, pTG->cbszCLASS2_OK, pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  1374. {
  1375. (MyDebugPrint (pTG, LOG_ALL, "FPTS= failed\n\r"));
  1376. // Ignore FPTS failure!!!
  1377. }
  1378. }
  1379. // Send last FDR
  1380. if(!Class2iModemDialog(pTG, pTG->cbszFDR, (UWORD) (strlen(pTG->cbszFDR) ),
  1381. STARTSENDMODE_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK, (C2PSTR)NULL))
  1382. {
  1383. err_status = T30_CALLFAIL;
  1384. return err_status;
  1385. }
  1386. FComXon(pTG, FALSE);
  1387. ICommGotDisconnect(pTG );
  1388. return err_status;
  1389. }
  1390. BOOL Class2GetModemMaker(PThrdGlbl pTG)
  1391. {
  1392. USHORT i;
  1393. // Initialize the current modem variable's (global) strings.
  1394. pTG->CurrentMFRSpec.szATI[0] = '\0';
  1395. pTG->CurrentMFRSpec.szMFR[0] = '\0';
  1396. pTG->CurrentMFRSpec.szMDL[0] = '\0';
  1397. // pTG->CurrentMFRSpec.szREV[0] = '\0';
  1398. // // Get the ATI - repsonse is in pTG->lpbResponseBuf2
  1399. // // For all responses, "ERROR" may come back - that is OK - we will
  1400. // // never match ERROR to an acceptable modem manufacturer name, model,
  1401. // // revision, etc.
  1402. // if(!Class2iModemDialog(cbszCLASS2_ATI, sizeof(cbszCLASS2_ATI)-1,
  1403. // ANS_LOCALCOMMAND_TIMEOUT, TRUE, 0, cbszCLASS2_OK,
  1404. // cbszCLASS2_ERROR, (C2PSTR) NULL))
  1405. // {
  1406. // (MyDebugPrint (pTG, LOG_ALL, "ATI failed\n\r"));
  1407. // // Ignore ATI failure!!!
  1408. // }
  1409. // else
  1410. // {
  1411. // // copy ATI answer into ATI variable
  1412. // for (i=0; i<MFR_SIZE; i++)
  1413. // pTG->CurrentMFRSpec.szATI[i] = pTG->lpbResponseBuf2[i];
  1414. // }
  1415. //
  1416. // (MyDebugPrint (pTG, LOG_ALL, "Received ATI %s\r", (LPSTR)(&(pTG->lpbResponseBuf2))));
  1417. // Get the FMFR - repsonse is in pTG->lpbResponseBuf2
  1418. if(!Class2iModemDialog(pTG, pTG->cbszCLASS2_FMFR, (UWORD) (strlen(pTG->cbszCLASS2_FMFR) ),
  1419. ANS_LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  1420. pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  1421. {
  1422. (MyDebugPrint (pTG, LOG_ALL, "FMFR failed\n\r"));
  1423. // Ignore FMFR failure!!!
  1424. }
  1425. else
  1426. {
  1427. // copy FMFR answer into FMFR variable
  1428. for (i=0; i<MFR_SIZE; i++)
  1429. pTG->CurrentMFRSpec.szMFR[i] = pTG->lpbResponseBuf2[i];
  1430. }
  1431. (MyDebugPrint (pTG, LOG_ALL, "Received FMFR %s\r", (LPSTR)(&(pTG->lpbResponseBuf2))));
  1432. // Get the FMDL - repsonse is in pTG->lpbResponseBuf2
  1433. if(!Class2iModemDialog(pTG, pTG->cbszCLASS2_FMDL, (UWORD) (strlen(pTG->cbszCLASS2_FMDL) ),
  1434. ANS_LOCALCOMMAND_TIMEOUT, TRUE, 0, pTG->cbszCLASS2_OK,
  1435. pTG->cbszCLASS2_ERROR, (C2PSTR) NULL))
  1436. {
  1437. (MyDebugPrint (pTG, LOG_ALL, "FMDL failed\n\r"));
  1438. // Ignore FMDL failure!!!
  1439. }
  1440. else
  1441. {
  1442. // copy FMDL answer into FMDL variable
  1443. for (i=0; i<MFR_SIZE; i++)
  1444. pTG->CurrentMFRSpec.szMDL[i] = pTG->lpbResponseBuf2[i];
  1445. }
  1446. (MyDebugPrint (pTG, LOG_ALL, "Received FMDL %s\r", (LPSTR)(&(pTG->lpbResponseBuf2))));
  1447. // // Get the FREV - repsonse is in pTG->lpbResponseBuf2
  1448. // if(!Class2iModemDialog(cbszCLASS2_FREV, sizeof(cbszCLASS2_FREV)-1,
  1449. // ANS_LOCALCOMMAND_TIMEOUT, TRUE, 0, cbszCLASS2_OK,
  1450. // cbszCLASS2_ERROR, (C2PSTR) NULL))
  1451. // {
  1452. // (MyDebugPrint (pTG, LOG_ALL, "FREV failed\n\r"));
  1453. // // Ignore FREV failure!!!
  1454. // }
  1455. // else
  1456. // {
  1457. // // copy FREV answer into REV variable
  1458. // for (i=0; i<MFR_SIZE; i++)
  1459. // pTG->CurrentMFRSpec.szREV[i] = pTG->lpbResponseBuf2[i];
  1460. // }
  1461. // (MyDebugPrint (pTG, LOG_ALL, "Received REV %s\r", (LPSTR)(&(pTG->lpbResponseBuf2))));
  1462. return TRUE;
  1463. }
  1464. void Class2SetMFRSpecific(PThrdGlbl pTG, LPSTR lpszSection)
  1465. {
  1466. USHORT iIndex, iFoundMFR,iFoundMDL;
  1467. LPMFRSPEC lpmfrMatched;
  1468. (MyDebugPrint (pTG, LOG_ALL, "Entering Class2SetMFRSpecific\n\r"));
  1469. // Find the index into the table that corresponds most closely
  1470. // to the modem. If we can't find the mfr and model, find a mfr
  1471. // that matches (use the last one). If neither, use the default
  1472. // last entry.
  1473. // Look for Manufacturer name
  1474. iIndex = 0;
  1475. iFoundMFR = 0;
  1476. iFoundMDL = 0;
  1477. (MyDebugPrint (pTG, LOG_ALL, "Entering search table loop\n\r"));
  1478. while (Class2ModemTable[iIndex].szMFR[0] != '\0')
  1479. {
  1480. lpmfrMatched = &(Class2ModemTable[iIndex]);
  1481. // Look and see if the current name matches
  1482. // the name in the list.
  1483. if(Class2_fstrstr( (LPSTR) pTG->CurrentMFRSpec.szMFR,
  1484. (LPSTR) lpmfrMatched->szMFR) != NULL)
  1485. {
  1486. // Found a match!
  1487. (MyDebugPrint (pTG, LOG_ALL, "MATCHED MANUFACTURER NAME: %s %s\n\r",
  1488. (LPSTR)(&pTG->CurrentMFRSpec.szMFR),
  1489. (LPSTR)(&(lpmfrMatched->szMFR)) ));
  1490. iFoundMFR=iIndex;
  1491. //Now see if this matches the model number, too.
  1492. if(Class2_fstrstr( (LPSTR) pTG->CurrentMFRSpec.szMDL,
  1493. (LPSTR) lpmfrMatched->szMDL) != NULL)
  1494. {
  1495. //Got a MDL match, too! Stop looking.
  1496. iFoundMDL = iIndex;
  1497. (MyDebugPrint (pTG, LOG_ALL, "MATCHED MODEL: %s %s\n\r", (LPSTR)(&pTG->CurrentMFRSpec.szMDL), (LPSTR)(&(lpmfrMatched->szMDL)) ));
  1498. break;
  1499. }
  1500. }
  1501. iIndex++;
  1502. }
  1503. // We now either have the modem match or are using the defaults!
  1504. if (iFoundMFR != 0) lpmfrMatched = &Class2ModemTable[iFoundMFR];
  1505. else lpmfrMatched = &Class2ModemTable[iIndex];
  1506. // Set proper BOR for receive and send
  1507. pTG->CurrentMFRSpec.iSendBOR = lpmfrMatched->iSendBOR;
  1508. pTG->CurrentMFRSpec.iReceiveBOR = lpmfrMatched->iReceiveBOR;
  1509. pTG->CurrentMFRSpec.fSWFBOR = lpmfrMatched->fSWFBOR;
  1510. // Set the DC2 string - this is used in receive mode
  1511. // after sending the FDR to tell the modem we are ready
  1512. // to receive data. The standard says it should be a Dc2
  1513. // (^R). But, some modems use ^Q
  1514. pTG->CurrentMFRSpec.szDC2[0] = lpmfrMatched->szDC2[0];
  1515. // Set the Sierra and Exar flags flag
  1516. pTG->CurrentMFRSpec.bIsSierra = lpmfrMatched->bIsSierra;
  1517. pTG->CurrentMFRSpec.bIsExar = lpmfrMatched->bIsExar;
  1518. pTG->CurrentMFRSpec.fSkipCtrlQ = lpmfrMatched->fSkipCtrlQ;
  1519. (MyDebugPrint (pTG, LOG_ALL, "Leaving Class2SetMFRSpecific\n\r"));
  1520. }
  1521. BOOL Class2Parse(PThrdGlbl pTG, CL2_COMM_ARRAY *cl2_comm, BYTE lpbBuf[])
  1522. {
  1523. int i,
  1524. j,
  1525. comm_numb = 0,
  1526. parameters;
  1527. BYTE switch_char,
  1528. char_1,
  1529. char_2;
  1530. char c;
  1531. BOOL found_command = FALSE;
  1532. #define STRING_PARAMETER 1
  1533. #define NUMBER_PARAMETERS 2
  1534. for(i = 0; lpbBuf[i] != '\0'; ++i)
  1535. {
  1536. switch ( lpbBuf[i] )
  1537. {
  1538. case 'C':
  1539. if (lpbBuf[++i] == 'O' && lpbBuf[++i] == 'N')
  1540. {
  1541. cl2_comm->command[comm_numb++] = CL2DCE_CONNECT;
  1542. for(; lpbBuf[i] != '\r'; ++i )
  1543. ;
  1544. }
  1545. else
  1546. {
  1547. (MyDebugPrint (pTG, LOG_ALL, "Parse: Bad First C values\n\r"));
  1548. return FALSE;
  1549. }
  1550. break;
  1551. case 'O':
  1552. if (lpbBuf[++i] == 'K' )
  1553. {
  1554. cl2_comm->command[comm_numb++] = CL2DCE_OK;
  1555. for(; lpbBuf[i] != '\r'; ++i )
  1556. ;
  1557. }
  1558. else
  1559. {
  1560. (MyDebugPrint (pTG, LOG_ALL, "Parse: Bad O values\n\r"));
  1561. return FALSE;
  1562. }
  1563. break;
  1564. case 0x11:
  1565. cl2_comm->command[comm_numb++] = CL2DCE_XON;
  1566. break;
  1567. case '+':
  1568. if( lpbBuf[++i] != 'F' )
  1569. {
  1570. (MyDebugPrint (pTG, LOG_ALL, "Parse: Bad + values\n\r"));
  1571. return FALSE;
  1572. }
  1573. switch_char = lpbBuf[++i];
  1574. char_1 = lpbBuf[++i];
  1575. char_2 = lpbBuf[++i];
  1576. // (MyDebugPrint (pTG, LOG_ALL, "Parse: in + command - %c%c%c \n\r",
  1577. // switch_char, char_1, char_2));
  1578. switch ( switch_char )
  1579. {
  1580. case 'C':
  1581. // Connect Message +FCON.
  1582. if ( char_1 == 'O' && char_2 == 'N' )
  1583. {
  1584. cl2_comm->command[comm_numb] = CL2DCE_FCON;
  1585. parameters = FALSE;
  1586. }
  1587. // Report of Remote ID. +FCIG.
  1588. else if (char_1 == 'I' && char_2 == 'G' )
  1589. {
  1590. cl2_comm->command[comm_numb] = CL2DCE_FCIG;
  1591. parameters = STRING_PARAMETER;
  1592. }
  1593. // Prepare to receive prompt. +FCFR.
  1594. else if ( char_1 == 'F' && char_2 == 'R' )
  1595. {
  1596. cl2_comm->command[comm_numb] = CL2DCE_FCFR;
  1597. parameters = FALSE;
  1598. }
  1599. // Report the Remote ID CSI +FCSI.
  1600. else if ( char_1 == 'S' && char_2 == 'I' )
  1601. {
  1602. cl2_comm->command[comm_numb] = CL2DCE_FCSI;
  1603. parameters = STRING_PARAMETER;
  1604. }
  1605. else
  1606. {
  1607. (MyDebugPrint (pTG, LOG_ALL, "Parse: Bad C values\n\r"));
  1608. return FALSE;
  1609. }
  1610. break;
  1611. case 'D':
  1612. // Report DCS frame information +FDCS.
  1613. if ( char_1 == 'C' && char_2 == 'S' )
  1614. {
  1615. cl2_comm->command[comm_numb] = CL2DCE_FDCS;
  1616. parameters = NUMBER_PARAMETERS;
  1617. }
  1618. // Report DIS frame information +FDIS.
  1619. else if ( char_1 == 'I' && char_2 == 'S' )
  1620. {
  1621. cl2_comm->command[comm_numb] = CL2DCE_FDIS;
  1622. parameters = NUMBER_PARAMETERS;
  1623. }
  1624. // Report DTC frame information +FDTC.
  1625. else if ( char_1 == 'T' && char_2 == 'C' )
  1626. {
  1627. cl2_comm->command[comm_numb] = CL2DCE_FDTC;
  1628. parameters = NUMBER_PARAMETERS;
  1629. }
  1630. else
  1631. {
  1632. (MyDebugPrint (pTG, LOG_ALL, "Parse: Bad D values\n\r"));
  1633. return FALSE;
  1634. }
  1635. break;
  1636. case 'E':
  1637. // Post page message report. +FET.
  1638. if ( char_1 == 'T' )
  1639. {
  1640. --i;
  1641. cl2_comm->command[comm_numb] = CL2DCE_FET;
  1642. parameters = NUMBER_PARAMETERS;
  1643. }
  1644. else
  1645. {
  1646. (MyDebugPrint (pTG, LOG_ALL, "Parse: Bad E values\n\r"));
  1647. return FALSE;
  1648. }
  1649. break;
  1650. case 'H':
  1651. // Debug report transmitted HDLC frames +FHT
  1652. if ( char_1 == 'T' )
  1653. {
  1654. --i;
  1655. cl2_comm->command[comm_numb] = CL2DCE_FHT;
  1656. parameters = STRING_PARAMETER;
  1657. }
  1658. // Debug report received HDLC frames +FHR
  1659. else if ( char_1 == 'R' )
  1660. {
  1661. --i;
  1662. cl2_comm->command[comm_numb] = CL2DCE_FHR;
  1663. parameters = STRING_PARAMETER;
  1664. }
  1665. // Report hang up. +FHNG.
  1666. else if ( char_1 == 'N' && char_2 == 'G' )
  1667. {
  1668. cl2_comm->command[comm_numb] = CL2DCE_FHNG;
  1669. parameters = NUMBER_PARAMETERS;
  1670. }
  1671. else
  1672. {
  1673. (MyDebugPrint (pTG, LOG_ALL, "Parse: Bad H values\n\r"));
  1674. return FALSE;
  1675. }
  1676. break;
  1677. case 'N':
  1678. // Report NSF frame reciept.
  1679. if ( char_1 == 'S' && char_2 == 'F' )
  1680. {
  1681. cl2_comm->command[comm_numb] = CL2DCE_FNSF;
  1682. parameters = NUMBER_PARAMETERS;
  1683. }
  1684. // Report NSS frame reciept.
  1685. else if ( char_1 == 'S' && char_2 == 'S' )
  1686. {
  1687. cl2_comm->command[comm_numb] = CL2DCE_FNSS;
  1688. parameters = NUMBER_PARAMETERS;
  1689. }
  1690. // Report NSC frame reciept.
  1691. else if ( char_1 == 'S' && char_2 == 'C' )
  1692. {
  1693. cl2_comm->command[comm_numb] = CL2DCE_FNSC;
  1694. parameters = NUMBER_PARAMETERS;
  1695. }
  1696. else
  1697. {
  1698. (MyDebugPrint (pTG, LOG_ALL, "Parse: Bad N values\n\r"));
  1699. return FALSE;
  1700. }
  1701. break;
  1702. case 'P':
  1703. // Report poll request. +FPOLL
  1704. if ( char_1 == 'O' && char_2 == 'L' )
  1705. {
  1706. cl2_comm->command[comm_numb] = CL2DCE_FPOLL;
  1707. parameters = FALSE;
  1708. }
  1709. // Page Transfer Status Report +FPTS.
  1710. else if ( char_1 == 'T' && char_2 == 'S' )
  1711. {
  1712. cl2_comm->command[comm_numb] = CL2DCE_FPTS;
  1713. parameters = NUMBER_PARAMETERS;
  1714. }
  1715. else
  1716. {
  1717. (MyDebugPrint (pTG, LOG_ALL, "Parse: Bad P values\n\r"));
  1718. return FALSE;
  1719. }
  1720. break;
  1721. case 'T':
  1722. // Report remote ID +FTSI.
  1723. if ( char_1 == 'S' && char_2 == 'I' )
  1724. {
  1725. cl2_comm->command[comm_numb] = CL2DCE_FTSI;
  1726. parameters = STRING_PARAMETER;
  1727. }
  1728. else
  1729. {
  1730. (MyDebugPrint (pTG, LOG_ALL, "Parse: Bad T values\n\r"));
  1731. return FALSE;
  1732. }
  1733. break;
  1734. case 'V':
  1735. // Report voice request +FVOICE.
  1736. if ( char_1 == 'O' && char_2 == 'I' )
  1737. {
  1738. cl2_comm->command[comm_numb] = CL2DCE_FVOICE;
  1739. parameters = FALSE;
  1740. }
  1741. else
  1742. {
  1743. (MyDebugPrint (pTG, LOG_ALL, "Parse: Bad V values\n\r"));
  1744. return FALSE;
  1745. }
  1746. }
  1747. // Transfer the associated paramters to the parameter array.
  1748. if ( parameters == NUMBER_PARAMETERS)
  1749. {
  1750. for(i+=1,j=0; lpbBuf[i] != '\r' && lpbBuf[i] != '\0'; ++i)
  1751. {
  1752. // Skip past the non numeric characters.
  1753. if ( lpbBuf[i] < '0' || lpbBuf[i] > '9' ) continue;
  1754. /* Convert the character representation of the numeric
  1755. parameter into a true number, and store in the
  1756. parameter list. */
  1757. cl2_comm->parameters[comm_numb][j] = 0;
  1758. for(; lpbBuf[i] >= '0' && lpbBuf[i] <= '9'; ++i)
  1759. {
  1760. cl2_comm->parameters[comm_numb][j] *= 10;
  1761. cl2_comm->parameters[comm_numb][j] += lpbBuf[i] - '0';
  1762. }
  1763. i--; // the last for loop advanced 'i' past the numeric.
  1764. j++; // get set up for next parameter
  1765. }
  1766. }
  1767. else if (parameters == STRING_PARAMETER )
  1768. {
  1769. // Skip the : that follows the +f command (eg +FTSI:)
  1770. if (lpbBuf[i+1] == ':') i++;
  1771. // Also skip the " that follows the :
  1772. if (lpbBuf[i+1] == '\"') i++;
  1773. // Also skip leading blanks
  1774. while (lpbBuf[i+1] == ' ') i++;
  1775. for(i+=1, j=0; (c = lpbBuf[i]) != '\r' && c != '\n' &&
  1776. c != '\0'; ++i, ++j)
  1777. {
  1778. cl2_comm->parameters[comm_numb][j] = c;
  1779. }
  1780. // Skip the trailing "
  1781. if ((j > 0) && (cl2_comm->parameters[comm_numb][j - 1] == '\"')) j--;
  1782. // Also skip the trailing blanks
  1783. for ( ; (j > 0) && (cl2_comm->parameters[comm_numb][j - 1] == ' '); j--);
  1784. cl2_comm->parameters[comm_numb][j] = '\0';
  1785. }
  1786. // No parameters, so just skip to end of line.
  1787. else
  1788. {
  1789. for(; (c=lpbBuf[i]) != '\r'
  1790. && c != '\n' && c != '\0'; ++i)
  1791. ;
  1792. }
  1793. // Increment command count.
  1794. ++comm_numb;
  1795. break;
  1796. default:
  1797. break;
  1798. }
  1799. }
  1800. cl2_comm->comm_count = (USHORT)comm_numb;
  1801. return TRUE;
  1802. }