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.

1977 lines
78 KiB

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