Leaked source code of windows server 2003
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.

1698 lines
60 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. class20.c
  5. Abstract:
  6. This is the main source for Classes 2 and 2.0 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. #define USE_DEBUG_CONTEXT DEBUG_CONTEXT_T30_CLASS2
  13. #include "prep.h"
  14. #include "efaxcb.h"
  15. #include "tiff.h"
  16. #include "glbproto.h"
  17. #include "t30gl.h"
  18. #include "cl2spec.h"
  19. #include "psslog.h"
  20. #define FILE_ID FILE_ID_CL2AND20
  21. #include "pssframe.h"
  22. #define STRSAFE_NO_DEPRECATE
  23. #include <strsafe.h>
  24. WORD Class2CodeToBPS[16] =
  25. {
  26. /* V27_2400 0 */ 2400,
  27. /* V27_4800 1 */ 4800,
  28. /* V29_V17_7200 2 */ 7200,
  29. /* V29_V17_9600 3 */ 9600,
  30. /* V33_V17_12000 4 */ 12000,
  31. /* V33_V17_14400 5 */ 14400,
  32. 0,
  33. 0,
  34. 0,
  35. 0,
  36. 0,
  37. 0,
  38. 0,
  39. 0,
  40. 0,
  41. 0
  42. };
  43. #define CLASS2_MAX_CODE_TO_BPS 15
  44. // Speeds for Class2HayesSyncSpeed to try
  45. UWORD rguwClass2Speeds[] = {19200, 9600, 2400, 1200, 0};
  46. BOOL ParseFPTS_SendAck(PThrdGlbl pTG)
  47. {
  48. BOOL fPageAck = FALSE;
  49. BOOL fFoundFPTS = FALSE;
  50. UWORD count;
  51. DEBUG_FUNCTION_NAME("ParseFPTS_SendAck");
  52. // Acknowledge that we sent the page
  53. // Parse the FPTS response and see if the page is good or bad.
  54. for (count=0; count < pTG->class2_commands.comm_count; ++count)
  55. {
  56. switch (pTG->class2_commands.command[count])
  57. {
  58. case CL2DCE_FPTS:
  59. fFoundFPTS = TRUE;
  60. switch(pTG->class2_commands.parameters[count][0])
  61. {
  62. case 1: DebugPrintEx(DEBUG_MSG,"Found good FPTS");
  63. fPageAck = TRUE;
  64. // Exar hack!!!
  65. // Exar modems give FPTS:1 for good pages and
  66. // FPTS:1,2,0,0 for bad. So, look for the 1,2
  67. // if this is an EXAR. Otherwise, 1 means good.
  68. if (pTG->CurrentMFRSpec.bIsExar)
  69. {
  70. if (pTG->class2_commands.parameters[count][1] == 2)
  71. {
  72. DebugPrintEx(DEBUG_ERR,"Nope - really Found bad FPTS");
  73. fPageAck = FALSE;
  74. }
  75. }
  76. else
  77. {
  78. PSSLogEntry(PSS_MSG, 1, "Received MCF");
  79. }
  80. break;
  81. case 2: PSSLogEntry(PSS_WRN, 1, "Received RTN");
  82. fPageAck = FALSE;
  83. break;
  84. case 3: PSSLogEntry(PSS_WRN, 1, "Received RTP");
  85. fPageAck = TRUE; // After RTP, we send the next page!
  86. break;
  87. case 4: PSSLogEntry(PSS_WRN, 1, "Received PIN");
  88. break;
  89. case 5: PSSLogEntry(PSS_WRN, 1, "Received PIP");
  90. break;
  91. default:PSSLogEntry(PSS_WRN, 1, "Received unknown response");
  92. }
  93. break;
  94. default:
  95. break;
  96. }
  97. }
  98. if (!fFoundFPTS)
  99. {
  100. PSSLogEntry(PSS_WRN, 1, "Didn't receive FPTS");
  101. }
  102. return fPageAck;
  103. }
  104. USHORT Class2Dial(PThrdGlbl pTG, LPSTR lpszDial)
  105. {
  106. UWORD uwLen,
  107. uwDialStringLen;
  108. ULONG ulTimeout;
  109. SWORD swLen;
  110. USHORT uRet;
  111. BYTE bBuf[DIALBUFSIZE];
  112. char chMod = pTG->NCUParams2.chDialModifier;
  113. DWORD dwDialTime;
  114. DEBUG_FUNCTION_NAME("Class2Dial");
  115. // Send the predial command
  116. if (pTG->lpCmdTab->szPreDial && (swLen=(SWORD)_fstrlen(pTG->lpCmdTab->szPreDial)))
  117. {
  118. if (Class2iModemDialog( pTG,
  119. (LPSTR)pTG->lpCmdTab->szPreDial,
  120. swLen,
  121. 10000L,
  122. 0,
  123. TRUE,
  124. pTG->cbszCLASS2_OK,
  125. pTG->cbszCLASS2_ERROR,
  126. (C2PSTR)NULL) != 1)
  127. {
  128. DebugPrintEx(DEBUG_WRN,"Error on User's PreDial string: %s", (LPSTR)pTG->lpCmdTab->szPreDial);
  129. }
  130. }
  131. // If the dial string already has a T or P prefix, we use that
  132. // instead.
  133. {
  134. char c = 0;
  135. while ((c=*lpszDial) && c==' ')
  136. {
  137. lpszDial++;
  138. }
  139. if (c=='t'|| c=='T' || c=='p'|| c=='P')
  140. {
  141. chMod = c;
  142. lpszDial++;
  143. while((c=*lpszDial) && c==' ')
  144. {
  145. lpszDial++;
  146. }
  147. }
  148. }
  149. uwLen = (UWORD)wsprintf(bBuf, pTG->cbszCLASS2_DIAL,chMod, (LPSTR)lpszDial);
  150. // Need to set an approriate timeout here. A minimum of 15secs is too short
  151. // (experiment calling machines within a PABX), plus one has to give extra
  152. // time for machines that pick up after 2 or 4 rings and also for long distance
  153. // calls. I take a minumum of 30secs and add 3secs for each digits over 7
  154. // (unless it's pulse dial in which case I add 8secs/digit).
  155. // (I'm assuming that a long-distance call will take a minimum of 8 digits
  156. // anywhere in ths world!). Fax machines I've tested wait about 30secs
  157. // independent of everything.
  158. uwDialStringLen = (SWORD)_fstrlen(lpszDial);
  159. ulTimeout = DIAL_TIMEOUT;
  160. if (uwDialStringLen > 7)
  161. {
  162. ulTimeout += ((chMod=='p' || chMod=='P')?8000:3000) * (uwDialStringLen - 7);
  163. }
  164. // If user aborts during one of the pre-dial commands (AT+FLID, etc.),
  165. // that command fails, but Class2xSend continues. Therefore, check for
  166. // abort here.
  167. if(pTG->fAbortRequested)
  168. {
  169. DebugPrintEx(DEBUG_ERR,"Class2Dial aborting");
  170. Class2ModemHangup(pTG);
  171. return CONNECT_ERROR;
  172. }
  173. dwDialTime = GetTickCount();
  174. LogDialCommand(pTG, pTG->cbszCLASS2_DIAL, chMod, strlen(lpszDial));
  175. uRet = Class2iModemDialog( pTG,
  176. (LPB)bBuf,
  177. uwLen,
  178. ulTimeout,
  179. 0,
  180. FALSE,
  181. pTG->cbszFCON,
  182. pTG->cbszCLASS2_BUSY,
  183. pTG->cbszCLASS2_NOANSWER,
  184. pTG->cbszCLASS2_NODIALTONE,
  185. pTG->cbszCLASS2_ERROR,
  186. pTG->cbszCLASS2_NOCARRIER,
  187. (NPSTR)NULL);
  188. // If it was "ERROR", try again - maybe the predial command screwed
  189. // up somehow and left and ERROR hanging around?
  190. if (uRet == 5)
  191. {
  192. LogDialCommand(pTG, pTG->cbszCLASS2_DIAL, chMod, strlen(lpszDial));
  193. uRet = Class2iModemDialog( pTG,
  194. (LPB)bBuf,
  195. uwLen,
  196. ulTimeout,
  197. 0,
  198. FALSE,
  199. pTG->cbszFCON,
  200. pTG->cbszCLASS2_BUSY,
  201. pTG->cbszCLASS2_NOANSWER,
  202. pTG->cbszCLASS2_NODIALTONE,
  203. pTG->cbszCLASS2_ERROR,
  204. pTG->cbszCLASS2_NOCARRIER,
  205. (NPSTR)NULL);
  206. }
  207. switch(uRet)
  208. {
  209. case CONNECT_TIMEOUT: if (pTG->fFoundFHNG)
  210. {
  211. PSSLogEntry(PSS_ERR, 1, "Call was disconnected");
  212. }
  213. else
  214. {
  215. PSSLogEntry(PSS_ERR, 1, "Response - timeout");
  216. }
  217. pTG->fFatalErrorWasSignaled = 1;
  218. SignalStatusChange(pTG, FS_NO_ANSWER);
  219. break;
  220. case CONNECT_OK: PSSLogEntry(PSS_MSG, 1, "Response - +FCON");
  221. pTG->fReceivedHDLCflags = TRUE;
  222. break;
  223. case CONNECT_BUSY: PSSLogEntry(PSS_ERR, 1, "Response - BUSY");
  224. pTG->fFatalErrorWasSignaled = 1;
  225. SignalStatusChange(pTG, FS_BUSY);
  226. break;
  227. case CONNECT_NOANSWER: PSSLogEntry(PSS_ERR, 1, "Response - NOANSWER");
  228. pTG->fFatalErrorWasSignaled = 1;
  229. SignalStatusChange(pTG, FS_NO_ANSWER);
  230. break;
  231. case CONNECT_NODIALTONE: PSSLogEntry(PSS_ERR, 1, "Response - NODIALTONE");
  232. pTG->fFatalErrorWasSignaled = 1;
  233. SignalStatusChange(pTG, FS_NO_DIAL_TONE);
  234. break;
  235. case CONNECT_ERROR: PSSLogEntry(PSS_ERR, 1, "Response - ERROR");
  236. pTG->fFatalErrorWasSignaled = 1;
  237. SignalStatusChange(pTG, FS_NO_ANSWER);
  238. break;
  239. case 6: {
  240. DWORD dwDelta = GetTickCount() - dwDialTime;
  241. PSSLogEntry(PSS_ERR, 1, "Response - NO CARRIER");
  242. if (dwDelta < 5000L)
  243. {
  244. DebugPrintEx(DEBUG_WRN,"Dial: Pretending it's BUSY");
  245. pTG->fFatalErrorWasSignaled = 1;
  246. SignalStatusChange(pTG, FS_BUSY);
  247. uRet = CONNECT_BUSY;
  248. }
  249. else
  250. {
  251. DebugPrintEx(DEBUG_WRN,"Dial: Pretending it's TIMEOUT");
  252. pTG->fFatalErrorWasSignaled = 1;
  253. SignalStatusChange(pTG, FS_NO_ANSWER);
  254. uRet = CONNECT_TIMEOUT;
  255. }
  256. }
  257. break;
  258. default: uRet = CONNECT_ERROR;
  259. break;
  260. }
  261. if (uRet != CONNECT_OK)
  262. {
  263. if (!Class2ModemHangup(pTG ))
  264. {
  265. return CONNECT_ERROR;
  266. }
  267. }
  268. return uRet;
  269. }
  270. USHORT Class2Answer(PThrdGlbl pTG)
  271. {
  272. USHORT uRet;
  273. SWORD swLen;
  274. ULONG ulWaitTime;
  275. DEBUG_FUNCTION_NAME("Class2Answer");
  276. // Default time we will wait after getting right number of rings
  277. // to allow input buffer to flush
  278. ulWaitTime = 500L;
  279. // We may still have an "OK" coming from the modem as a result of the
  280. // ATS1 command. We need to wait a bit and flush it. In most cases we
  281. // just wait 500 milliseconds. But, if we saw a 000 from the ATS1, we
  282. // broke immediately out of the loop above, setting ulWaitTime to be
  283. // the approximate wait we need before answering the phone.
  284. startTimeOut(pTG, &pTG->toAnswer, ulWaitTime);
  285. while (checkTimeOut(pTG, &pTG->toAnswer))
  286. {
  287. }
  288. FComFlush(pTG );
  289. // Send the preanswer command
  290. if (pTG->lpCmdTab->szPreAnswer && (swLen=(SWORD)_fstrlen(pTG->lpCmdTab->szPreAnswer)))
  291. {
  292. if (Class2iModemDialog( pTG,
  293. (LPSTR)pTG->lpCmdTab->szPreAnswer,
  294. swLen,
  295. 10000L,
  296. 0,
  297. TRUE,
  298. pTG->cbszCLASS2_OK,
  299. pTG->cbszCLASS2_ERROR,
  300. (C2PSTR)NULL) != 1)
  301. {
  302. DebugPrintEx(DEBUG_WRN,"Error on User's PreAnswer str: %s", (LPSTR)pTG->lpCmdTab->szPreAnswer);
  303. }
  304. }
  305. #define ANSWER_TIMEOUT 35000
  306. // Need to wait reasonably long, so that we don't give up too easily
  307. // 7/25/95 JosephJ This used to be 15000. Changed to 35000 because
  308. // MWAVE devices needed that timeout. Also, T.30 says that callee
  309. // should try to negotiate for T1 seconds. T1 = 35 +/- 5s.
  310. /*
  311. * Send ATA command. The result will be stored in the global
  312. * variable pTG->lpbResponseBuf2. We will parse that in the Class2Receive
  313. * routine.
  314. */
  315. // Look for ERROR return first and try again if it happened
  316. if ((uRet = Class2iModemDialog( pTG,
  317. pTG->cbszATA,
  318. (UWORD)(strlen(pTG->cbszATA)),
  319. ANSWER_TIMEOUT,
  320. 0,
  321. TRUE,
  322. pTG->cbszCLASS2_OK,
  323. pTG->cbszCLASS2_FHNG,
  324. pTG->cbszCLASS2_ERROR,
  325. (C2PSTR) NULL)) == 3)
  326. {
  327. DebugPrintEx(DEBUG_ERR,"ATA returned ERROR on first try");
  328. // dunno why we try this a 2nd time. But this time if we get ERROR
  329. // dont exit. The Racal modem (bug#1982) gives ERROR followed by a
  330. // good response! Cant ignore ERROR the first time otherwise we'll
  331. // change the ATA--ERROR--ATA(repeat) behaviour which seems to be
  332. // explicitly desired for some cases. However we dont take any
  333. // action based on the return value of the 2nd try, so it's safe to
  334. // ignore ERROR here. Worst case we take longer to timeout.
  335. uRet = Class2iModemDialog( pTG,
  336. pTG->cbszATA,
  337. (UWORD)(strlen(pTG->cbszATA)),
  338. ANSWER_TIMEOUT,
  339. 0,
  340. TRUE,
  341. pTG->cbszCLASS2_OK,
  342. pTG->cbszCLASS2_FHNG,
  343. (C2PSTR) NULL);
  344. }
  345. // Should've used Class2xParse to detect +FHNG. However, the ATA dialogs had the
  346. // CLASS2_FHNG reply in them before FHNG detection was implemented into
  347. // Class2xParse. If these answers are removed, a modem that replies "+FHNG" and
  348. // then nothing (no "OK") would only fail on timeout here. So, in order not to
  349. // cause a regression on such (hypothetical) modems, I'm keeping the CLASS2_FHNG's.
  350. if (uRet==2)
  351. {
  352. pTG->fFoundFHNG = TRUE;
  353. }
  354. if ((uRet != 1) || (pTG->fFoundFHNG)) // a '1' return indicates OK.
  355. {
  356. DebugPrintEx(DEBUG_ERR,"Can't get OK after ATA");
  357. PSSLogEntry(PSS_ERR, 1, "Failed to answer - this call was not a fax call");
  358. pTG->fFatalErrorWasSignaled = 1;
  359. SignalStatusChangeWithStringId(pTG, FS_RECV_NOT_FAX_CALL, IDS_RECV_NOT_FAX_CALL);
  360. // try to hangup and sync with modem. This should work
  361. // even if phone is not really off hook
  362. if (!Class2ModemHangup(pTG))
  363. {
  364. DebugPrintEx(DEBUG_ERR,"Can't Hangup after ANSWERFAIL");
  365. }
  366. return CONNECT_ERROR;
  367. }
  368. else
  369. {
  370. DebugPrintEx(DEBUG_MSG,"ATA Received %s",(LPSTR)(&(pTG->lpbResponseBuf2)));
  371. pTG->fReceivedHDLCflags = TRUE;
  372. return CONNECT_OK;
  373. }
  374. }
  375. SWORD Class2ModemSync(PThrdGlbl pTG)
  376. {
  377. // The command used here must be guaranteed to be harmless,
  378. // side-effect free & non-dstructive. i.e. we can issue it
  379. // at any point in command mode without chnageing the state
  380. // of teh modem or disrupting anything.
  381. // ATZ does not qualify. AT does, I think.....
  382. SWORD ret_value;
  383. DEBUG_FUNCTION_NAME("Class2ModemSync");
  384. DebugPrintEx(DEBUG_MSG,"Calling Class2HayesSyncSpeed");
  385. ret_value = Class2HayesSyncSpeed( pTG,
  386. pTG->cbszCLASS2_ATTEN,
  387. (UWORD)(strlen(pTG->cbszCLASS2_ATTEN)));
  388. DebugPrintEx(DEBUG_MSG,"Class2HayesSyncSpeed returned %d ", ret_value);
  389. return ret_value;
  390. }
  391. BOOL Class2ModemHangup(PThrdGlbl pTG)
  392. {
  393. DEBUG_FUNCTION_NAME("Class2ModemHangup");
  394. PSSLogEntry(PSS_MSG, 0, "Phase E - Hang-up");
  395. PSSLogEntry(PSS_MSG, 1, "Hanging up");
  396. if (Class2HayesSyncSpeed( pTG,
  397. pTG->cbszCLASS2_HANGUP,
  398. (UWORD)(strlen(pTG->cbszCLASS2_HANGUP))) < 0)
  399. {
  400. DebugPrintEx(DEBUG_WRN,"Failed once");
  401. FComDTR(pTG, FALSE); // Lower DTR on stubborn hangups in ModemHangup
  402. Sleep(1000); // pause 1 second
  403. FComDTR(pTG, TRUE); // raise it again. Some modems return to cmd state
  404. // only when this is raised again
  405. if (Class2HayesSyncSpeed( pTG,
  406. pTG->cbszCLASS2_HANGUP,
  407. (UWORD)(strlen(pTG->cbszCLASS2_HANGUP))) < 0)
  408. {
  409. DebugPrintEx(DEBUG_ERR,"Failed again");
  410. return FALSE;
  411. }
  412. }
  413. DebugPrintEx(DEBUG_MSG,"HANGUP Completed");
  414. if (!iModemGoClass(pTG, 0))
  415. {
  416. return FALSE;
  417. }
  418. // Can also ignore this return value. Just for tidier cleanup
  419. DebugPrintEx(DEBUG_MSG,"Completed GoClass0");
  420. // Bug1982: Racal modem, doesnt accept ATA. So we send it a PreAnswer
  421. // command of ATS0=1, i.r. turning ON autoanswer. And we ignore the
  422. // ERROR response it gives to the subsequent ATAs. It then answers
  423. // 'automatically' and gives us all the right responses. On hangup
  424. // however we need to send an ATS0=0 to turn auto-answer off. The
  425. // ExitCommand is not sent at all in Class2 and in Class1 it is only
  426. // sent on releasing the modem, not between calls. So send an S0=0
  427. // after ATH0. If the modem doesnt like it we ignore the resp anyway.
  428. Class2iModemDialog( pTG,
  429. pTG->cbszCLASS2_CALLDONE,
  430. (UWORD)(strlen(pTG->cbszCLASS2_CALLDONE)),
  431. LOCALCOMMAND_TIMEOUT,
  432. 0,
  433. TRUE,
  434. pTG->cbszCLASS2_OK,
  435. pTG->cbszCLASS2_ERROR,
  436. (C2PSTR)NULL);
  437. return TRUE;
  438. }
  439. BOOL Class2ModemAbort(PThrdGlbl pTG)
  440. {
  441. DEBUG_FUNCTION_NAME("Class2ModemAbort");
  442. // If modem already reported +FHNG, no need telling it to abort
  443. if (!pTG->fFoundFHNG)
  444. {
  445. // Try to abort modem in reasonable fashion - send the
  446. // abort command and then send hangup. The abort command
  447. // should hangup, but I am not convinced it always does!!!
  448. // It should not hurt to hang up again (I hope).
  449. // We'll use a long timeout here to let the abort take place.
  450. if (!Class2iModemDialog(pTG,
  451. pTG->cbszCLASS2_ABORT,
  452. (UWORD)(strlen(pTG->cbszCLASS2_ABORT)),
  453. STARTSENDMODE_TIMEOUT,
  454. 1,
  455. TRUE,
  456. pTG->cbszCLASS2_OK,
  457. pTG->cbszCLASS2_ERROR,
  458. (C2PSTR) NULL))
  459. {
  460. //Ignore failure
  461. DebugPrintEx(DEBUG_ERR,"FK Failed");
  462. }
  463. }
  464. return Class2ModemHangup(pTG );
  465. }
  466. SWORD Class2HayesSyncSpeed(PThrdGlbl pTG, C2PSTR cbszCommand, UWORD uwLen)
  467. {
  468. /*
  469. Internal routine to synchronize with the modem's speed. Tries to
  470. get a response from the modem by trying the speeds in rglSpeeds
  471. in order (terminated by a 0). If fTryCurrent is nonzero, checks for
  472. a response before trying to reset the speeds.
  473. Returns the speed it found, 0 if they're in sync upon entry (only
  474. checked if fTryCurrent!=0), or -1 if it couldn't sync.
  475. */
  476. short ilWhich = 0;
  477. DEBUG_FUNCTION_NAME("Class2HayesSyncSpeed");
  478. for(;;)
  479. {
  480. if (Class2SyncModemDialog(pTG,cbszCommand,uwLen,pTG->cbszCLASS2_OK))
  481. {
  482. return (ilWhich>=0 ? rguwClass2Speeds[ilWhich] : 0);
  483. }
  484. /* failed. try next speed. */
  485. if (rguwClass2Speeds[++ilWhich]==0)
  486. {
  487. // Tried all speeds. No response
  488. DebugPrintEx(DEBUG_ERR,"Cannot Sync with Modem on Command %s", (LPSTR)cbszCommand);
  489. return -1;
  490. }
  491. if (!FComSetBaudRate(pTG, rguwClass2Speeds[ilWhich]))
  492. {
  493. return -1;
  494. }
  495. }
  496. }
  497. USHORT Class2ModemRecvBuf(PThrdGlbl pTG, LPBUFFER far* lplpbf, USHORT uTimeout)
  498. {
  499. USHORT uRet;
  500. DEBUG_FUNCTION_NAME("Class2ModemRecvBuf");
  501. *lplpbf = MyAllocBuf(pTG, MY_BIGBUF_SIZE);
  502. if (*lplpbf == NULL)
  503. {
  504. DebugPrintEx(DEBUG_ERR, "MyAllocBuf failed trying to allocate %d bytes", MY_BIGBUF_SIZE);
  505. return RECV_OUTOFMEMORY;
  506. }
  507. uRet = Class2ModemRecvData( pTG,
  508. (*lplpbf)->lpbBegBuf,
  509. (*lplpbf)->wLengthBuf,
  510. uTimeout,
  511. &((*lplpbf)->wLengthData));
  512. if (!((*lplpbf)->wLengthData))
  513. {
  514. MyFreeBuf(pTG, *lplpbf);
  515. *lplpbf = NULL;
  516. }
  517. else
  518. {
  519. // If necessary, bit-reverse...
  520. if (pTG->CurrentMFRSpec.fSWFBOR && pTG->CurrentMFRSpec.iReceiveBOR==1)
  521. {
  522. DebugPrintEx(DEBUG_WRN,"SWFBOR Enabled. bit-reversing data");
  523. cl2_flip_bytes( (*lplpbf)->lpbBegBuf, ((*lplpbf)->wLengthData));
  524. }
  525. }
  526. return uRet;
  527. }
  528. USHORT Class2ModemRecvData(PThrdGlbl pTG, LPB lpb, USHORT cbMax, USHORT uTimeout, USHORT far* lpcbRecv)
  529. {
  530. SWORD swEOF;
  531. startTimeOut(pTG, &pTG->toRecv, uTimeout);
  532. // 4th arg must be TRUE for Class2
  533. *lpcbRecv = FComFilterReadBuf(pTG, lpb, cbMax, &pTG->toRecv, TRUE, &swEOF);
  534. switch(swEOF)
  535. {
  536. case 1: // Class1 eof
  537. case -1: // Class2 eof
  538. return RECV_EOF;
  539. case 0:
  540. return RECV_OK;
  541. default:
  542. // fall through
  543. case -2:
  544. return RECV_ERROR;
  545. case -3:
  546. return RECV_TIMEOUT;
  547. }
  548. }
  549. BOOL Class2ModemSendMem(PThrdGlbl pTG, LPBYTE lpb, USHORT uCount)
  550. {
  551. DEBUG_FUNCTION_NAME("Class2ModemSendMem");
  552. if (!FComFilterAsyncWrite(pTG, lpb, uCount, FILTER_DLEZERO))
  553. {
  554. goto error;
  555. }
  556. return TRUE;
  557. error:
  558. DebugPrintEx(DEBUG_ERR,"Failed on AsyncWrite");
  559. FComOutFilterClose(pTG);
  560. FComXon(pTG, FALSE);
  561. return FALSE;
  562. }
  563. /*
  564. output:
  565. 0 - timeout
  566. 1 - OK
  567. 2 - ERROR
  568. */
  569. DWORD Class2ModemDrain(PThrdGlbl pTG)
  570. {
  571. DWORD dwResult = 0;
  572. DEBUG_FUNCTION_NAME("Class2ModemDrain");
  573. if (!FComDrain(pTG, TRUE, TRUE))
  574. {
  575. return FALSE;
  576. }
  577. // Must turn XON/XOFF off immediately *after* drain, but before we
  578. // send the next AT command, since Received frames have 0x13 or
  579. // even 0x11 in them!! MUST GO AFTER the getOK ---- See BELOW!!!!
  580. dwResult = Class2iModemDialog(pTG,
  581. NULL,
  582. 0,
  583. STARTSENDMODE_TIMEOUT,
  584. 0,
  585. TRUE,
  586. pTG->cbszCLASS2_OK,
  587. pTG->cbszCLASS2_ERROR,
  588. (C2PSTR)NULL);
  589. // Must change FlowControl State *after* getting OK because in Windows
  590. // this call takes 500 ms & resets chips, blows away data etc.
  591. // So do this *only* when you *know* both RX & TX are empty.
  592. // Turn off flow control.
  593. FComXon(pTG, FALSE);
  594. // FComDrain doesn't check for abort, and the dialog might succeed because of that
  595. // Therefore, check for it here.
  596. if (pTG->fAbortRequested)
  597. {
  598. return 0; // timeout
  599. }
  600. return dwResult;
  601. }
  602. #define ABORT_TIMEOUT 250
  603. UWORD Class2iModemDialog
  604. (
  605. PThrdGlbl pTG,
  606. LPSTR szSend,
  607. UWORD uwLen,
  608. ULONG ulTimeout,
  609. UWORD uwRepeatCount,
  610. BOOL fLogSend,
  611. ...
  612. )
  613. {
  614. /** Takes a command string, and it's lengt writes it out to the modem
  615. and tries to get one of the allowed responses. It writes the command
  616. out, waits ulTimeOut millisecs for a response. If it gets one of the
  617. expected responses it returns immediately.
  618. If it gets an unexpected/illegal response it tries (without any
  619. waiting) for subsequent lines to the same response. When all the
  620. lines (if > 1) of the response lines are exhausted, if none is among the
  621. expected responses, it writes the command again and tries again,
  622. until ulTimeout has expired. Note that if no response is received,
  623. the command will be written just once.
  624. The whole above thing will be repeated upto uwRepeatCount times
  625. if uwRepeatCount is non-zero
  626. <<<<<NOTE:::uwRepeatCount != 0 should not be used except for local sync>>>>>
  627. It returns when (a) one of the specified responses is received or
  628. (b) uwRepeatCount tries have failed (each having returned an
  629. illegal response or having returned no response in ulTimeout
  630. millsecs) or (c) the command write failed, in which
  631. case it returns immediately.
  632. It flushes the modem inque before each Command Write.
  633. Returns 0 on failure and the 1 based index of the successful
  634. response on success.
  635. This can be used in the following way:-
  636. for Local Dialogs (AT, AT+FTH=? etc), set ulTimeout to a lowish
  637. value, of the order of the transmission time of the longest
  638. possible (erroneous or correct) line of response plus the size
  639. of the command. eg. at 1200baud we have about 120cps = about
  640. 10ms/char. Therefore a timeout of about 500ms is more than
  641. adequate, except for really long command lines.
  642. for Local Sync dialogs, used to sync up with the modem which may
  643. be in an unsure state, use the same timeout, but also a repeat
  644. count of 2 or 3.
  645. for remote-driven dialogs, eg. AT+FRH=xx which returns a CONNECT
  646. after the flags have been received, and which may incur a delay
  647. before a response (ATDT is teh same. CONNECT is issued after a
  648. long delay & anything the DTE sends will abort the process).
  649. For these cases the caller should supply a long timeout and
  650. probably a repeatcount of 1, so that the
  651. routine will timeout after one try but go on issuing teh command
  652. as long as an error repsonse is received.
  653. For +FRH etc, the long timeout should be T1 or T2 in teh case of
  654. CommandRecv and ResponseRecv respectively.
  655. **/
  656. BYTE bReply[REPLYBUFSIZE];
  657. UWORD i, j, uwRet, uwWantCount;
  658. SWORD swNumRead;
  659. C2PSTR rgcbszWant[10] = {NULL};
  660. va_list args;
  661. LPTO lpto, lptoRead, lpto0;
  662. DEBUG_FUNCTION_NAME("Class2iModemDialog");
  663. // extract the (variable length) list of acceptable responses.
  664. // each is a C2SZ, code based 2 byte ptr
  665. va_start(args, fLogSend); // Ansi Defintion
  666. for(j=1; j<10; j++)
  667. {
  668. if((rgcbszWant[j] = va_arg(args, C2PSTR)) == NULL)
  669. {
  670. break;
  671. }
  672. }
  673. uwWantCount = j-1;
  674. va_end(args);
  675. pTG->lpbResponseBuf2[0] = 0;
  676. lpto = &pTG->toDialog;
  677. lpto0 = &pTG->toZero;
  678. // Try the dialog upto uwRepeatCount times
  679. for (uwRet=0, i=0; i<=uwRepeatCount; i++)
  680. {
  681. startTimeOut(pTG, lpto, ulTimeout);
  682. do
  683. {
  684. if(szSend)
  685. {
  686. // If a command is supplied, write it out, flushing input
  687. // first to get rid of spurious input.
  688. // FComInputFlush();
  689. FComFlush(pTG); // Need to flush output too?
  690. if (fLogSend)
  691. {
  692. PSSLogEntry(PSS_MSG, 2, "send: \"%s\"", szSend);
  693. }
  694. // Need to check that we are sending only ASCII or pre-stuffed data here
  695. if (!FComDirectSyncWriteFast(pTG, szSend, uwLen))
  696. {
  697. DebugPrintEx(DEBUG_ERR,"Modem Dialog Write timed Out");
  698. uwRet = 0;
  699. goto done;
  700. // If Write fails, fail & return immediately.
  701. // SetMyError() will already have been called.
  702. }
  703. }
  704. for (lptoRead=lpto;;startTimeOut(pTG, lpto0, ulTimeout), lptoRead=lpto0)
  705. {
  706. // get a CR-LF terminated line
  707. // for the first line use macro timeout, for multi-line
  708. // responses use 0 timeout.
  709. swNumRead = FComFilterReadLine(pTG, bReply, REPLYBUFSIZE-1, lptoRead);
  710. if(swNumRead < 0)
  711. {
  712. swNumRead = (-swNumRead); // error-but lets see what we got anyway
  713. }
  714. else if (swNumRead == 0)
  715. {
  716. goto timeout; // Timeout -- restart dialog or exit
  717. }
  718. if (swNumRead == 2 && bReply[0] == '\r' && bReply[1] == '\n')
  719. {
  720. continue; // blank line -- throw away & get another
  721. }
  722. // COPIED THIS FROM DUP FUNCTION IN MODEM.C!!
  723. // Fix Bug#1226. Elsa Microlink returns this garbage line in
  724. // response to AT+FDIS?, followed by the real reply. Since
  725. // we only look at the first line, we see only this garbage line
  726. // and we never see the real reply
  727. if (swNumRead==3 && bReply[0]==0x13 && bReply[1]=='\r' && bReply[2]=='\n')
  728. {
  729. continue;
  730. }
  731. PSSLogEntry(PSS_MSG, 2, "recv: \"%s\"", bReply);
  732. for(bReply[REPLYBUFSIZE-1]=0, j=0; j<=uwWantCount; j++)
  733. {
  734. if( rgcbszWant[j] && (strstr(bReply, rgcbszWant[j]) != NULL))
  735. {
  736. uwRet = j;
  737. // It matched!!!
  738. // Save this reply. This is used when checking
  739. // ATS1 responses
  740. goto end;
  741. }
  742. }
  743. // go to ulTimeout check. i.e. *don't* set fTimedOut
  744. // but don't exit either. Retry command and response until
  745. // timeout
  746. // We reach here it IFF we got a non blank reply, but it wasn't what
  747. // we wanted. Squirrel teh first line away somewhere so that we can
  748. // retrieve is later. We use this hack to get multi-line informational
  749. // responses to things like +FTH=? Very important to ensure that
  750. // blank-line replies don't get recorded here. (They may override
  751. // the preceding line that we need!).
  752. if ( (strlen(pTG->lpbResponseBuf2) + strlen(bReply) ) < RESPONSE_BUF_SIZE)
  753. {
  754. strncat(pTG->lpbResponseBuf2, bReply, (ARR_SIZE(pTG->lpbResponseBuf2) - strlen(pTG->lpbResponseBuf2) -1));
  755. }
  756. else
  757. {
  758. DebugPrintEx(DEBUG_ERR,"Response too long!");
  759. uwRet = 0;
  760. goto end;
  761. }
  762. // If +FHNG was received, an OK should follow.
  763. if (strstr(bReply, pTG->cbszCLASS2_FHNG) != NULL)
  764. {
  765. UWORD uwAns;
  766. // Check whether OK is already on the responses list
  767. for (uwAns=1; uwAns<=uwWantCount; uwAns++)
  768. {
  769. if (strstr(rgcbszWant[uwAns], pTG->cbszCLASS2_OK) != NULL)
  770. {
  771. break;
  772. }
  773. }
  774. if (uwAns > uwWantCount)
  775. {
  776. // OK is not on the list, add it as response #0. When the OK
  777. // comes, the dialog will terminate with response 0, and the caller
  778. // will know that the dialog failed.
  779. DebugPrintEx(DEBUG_MSG, "FHNG found during dialog, adding OK to want list");
  780. rgcbszWant[0] = pTG->cbszCLASS2_OK;
  781. }
  782. else
  783. {
  784. // OK is already on the wanted responses list, don't add anything. The
  785. // dialog will succeed with the original OK response, and the caller can
  786. // explicitely check pTG->fFoundFHNG
  787. DebugPrintEx(DEBUG_MSG, "FHNG found during dialog, OK already on want list");
  788. }
  789. }
  790. } // end of loop that reads lines until timeout
  791. // we come here only on timeout.
  792. } while (checkTimeOut(pTG, lpto));
  793. timeout:
  794. PSSLogEntryStrings(PSS_WRN, 2, &rgcbszWant[1], uwWantCount,
  795. "failed to receive expected response: ");
  796. // Need to send anychar to abort the previous command. Use "AT"
  797. PSSLogEntry(PSS_MSG, 2, "send: \"AT\"");
  798. FComFlush(pTG); // flush first--don't want some old garbage result
  799. FComDirectSyncWriteFast(pTG, "\rAT", 3);
  800. FComFlushInput(pTG); // flush input again
  801. FComDirectAsyncWrite(pTG, "\r", 1);
  802. startTimeOut(pTG, lpto0, ABORT_TIMEOUT);
  803. do
  804. {
  805. swNumRead = FComFilterReadLine(pTG, bReply, REPLYBUFSIZE-1, lpto0);
  806. }
  807. while(swNumRead==2 && bReply[0]=='\r'&& bReply[1]=='\n');
  808. // While we get a blank line. Get another.
  809. bReply[REPLYBUFSIZE-1] = 0;
  810. if (swNumRead != 0)
  811. {
  812. PSSLogEntry(PSS_MSG, 2, "recv: \"%s\"", bReply);
  813. }
  814. } // for i=0..RepeatCount
  815. end:
  816. if (uwRet == 0)
  817. {
  818. DebugPrintEx( DEBUG_ERR,
  819. "(%s) --> (%d)(%s, etc) Failed",
  820. (LPSTR)(szSend?szSend:"null"),
  821. uwWantCount,
  822. (LPSTR)rgcbszWant[1]);
  823. }
  824. else
  825. {
  826. DebugPrintEx(DEBUG_MSG,"GOT IT %d (%s)", uwRet, (LPSTR)(rgcbszWant[uwRet]));
  827. }
  828. done:
  829. // Parse modem notifications into pTG->class2_commands
  830. if (pTG->ModemClass == MODEM_CLASS2)
  831. {
  832. Class2Parse(pTG, &pTG->class2_commands, pTG->lpbResponseBuf2 );
  833. }
  834. else
  835. {
  836. Class20Parse(pTG, &pTG->class2_commands, pTG->lpbResponseBuf2 );
  837. }
  838. return uwRet;
  839. }
  840. /* Converts the code for a speed to the speed in BPS */
  841. // These are in the same order as the return values
  842. // for DIS/DCS frames defined in the Class 2 spec in
  843. // Table 8.4
  844. /* Converts a DCS min-scan field code into millisecs */
  845. // One array is for normal (100 dpi) res, the other for high (200 dpi) res...
  846. // The ordering of the arraies is based on the values that
  847. // are defined in filet30.h - THEY ARE NOT THE SAME AS THE VALUES
  848. // RETURNED IN THE DCS FRAME!!!! This is inconsistent with baud rate
  849. // but it is consistent with the Class 1 code...
  850. BYTE msPerLineNormalRes[8] = { 20, 5, 10, 20, 40, 40, 10, 0 };
  851. BYTE msPerLineHighRes[8] = { 20, 5, 10, 10, 40, 20, 5, 0 };
  852. USHORT Class2MinScanToBytesPerLine(PThrdGlbl pTG, BYTE Minscan, BYTE Baud, BYTE Resolution)
  853. {
  854. USHORT uStuff;
  855. BYTE ms;
  856. DEBUG_FUNCTION_NAME("Class2MinScanToBytesPerLine");
  857. uStuff = Class2CodeToBPS[Baud];
  858. if ( Resolution & AWRES_mm080_077)
  859. {
  860. ms = msPerLineHighRes[Minscan];
  861. }
  862. else
  863. {
  864. ms = msPerLineNormalRes[Minscan];
  865. }
  866. uStuff /= 100; // StuffBytes = (BPS * ms)/8000
  867. uStuff *= ms; // take care not to use longs
  868. uStuff /= 80; // or overflow WORD or lose precision
  869. uStuff += 1; // Rough fix for truncation problems
  870. DebugPrintEx(DEBUG_MSG,"Stuffing %d bytes", uStuff);
  871. return uStuff;
  872. }
  873. // Convert the SEND_CAPS or SEND_PARAMS BC structure into values used by
  874. // the +FDCC, +FDIS, and +FDT commands
  875. void Class2SetDIS_DCSParams
  876. (
  877. PThrdGlbl pTG,
  878. BCTYPE bctype,
  879. OUT LPUWORD Encoding,
  880. OUT LPUWORD Resolution,
  881. OUT LPUWORD PageWidth,
  882. OUT LPUWORD PageLength,
  883. OUT LPSTR szID,
  884. IN UINT cch
  885. )
  886. {
  887. LPBC lpbc;
  888. DEBUG_FUNCTION_NAME("Class2SetDIS_DCSParams");
  889. DebugPrintEx(DEBUG_MSG,"Type = %d", (USHORT)bctype);
  890. if (bctype == SEND_PARAMS)
  891. {
  892. lpbc = (LPBC)&pTG->bcSendParams;
  893. }
  894. else
  895. {
  896. lpbc = (LPBC)&pTG->bcSendCaps;
  897. }
  898. if (pTG->LocalID)
  899. {
  900. HRESULT hr = StringCchCopy(szID,cch,pTG->LocalID);
  901. if (FAILED(hr))
  902. {
  903. // we failed, nothing to do other than debug print.
  904. // the OUT param is null terminated.
  905. DebugPrintEx(DEBUG_WRN,"StringCchCopy failed (ec=0x%08X)",hr);
  906. }
  907. }
  908. switch(lpbc->Fax.Encoding)
  909. {
  910. case MH_DATA: *Encoding = 0;
  911. break;
  912. case MR_DATA:
  913. case (MR_DATA | MH_DATA): *Encoding = 1;
  914. break;
  915. case MMR_DATA:
  916. case (MMR_DATA | MH_DATA):
  917. case (MMR_DATA | MR_DATA):
  918. case (MMR_DATA | MR_DATA | MH_DATA): *Encoding = 3;
  919. break;
  920. default: DebugPrintEx(DEBUG_ERR,"Bad Encoding type %x",lpbc->Fax.Encoding);
  921. break;
  922. }
  923. if ( (lpbc->Fax.AwRes) & AWRES_mm080_077)
  924. {
  925. *Resolution = 1;
  926. }
  927. else if ( (lpbc->Fax.AwRes) & AWRES_mm080_038)
  928. {
  929. *Resolution = 0;
  930. }
  931. else
  932. {
  933. DebugPrintEx(DEBUG_ERR,"Bad Resolution type %x",lpbc->Fax.AwRes);
  934. }
  935. switch (lpbc->Fax.PageWidth & 0x3)
  936. {
  937. case WIDTH_A4: // 1728 pixels
  938. *PageWidth = 0;
  939. break;
  940. case WIDTH_B4: // 2048 pixels
  941. *PageWidth = 1;
  942. break;
  943. case WIDTH_A3: // 2432 pixels
  944. *PageWidth = 2;
  945. break;
  946. default: DebugPrintEx(DEBUG_ERR,"Bad PageWidth type %x", lpbc->Fax.PageWidth);
  947. break;
  948. }
  949. switch(lpbc->Fax.PageLength)
  950. {
  951. case LENGTH_A4: *PageLength = 0;
  952. break;
  953. case LENGTH_B4: *PageLength = 1;
  954. break;
  955. case LENGTH_UNLIMITED: *PageLength = 2;
  956. break;
  957. default: DebugPrintEx(DEBUG_ERR,"Bad PageLength type %x", lpbc->Fax.PageLength);
  958. break;
  959. }
  960. }
  961. /*++
  962. Routine Description:
  963. Copies a string, removing leading and trailing spaces
  964. Arguments:
  965. pszDest [out] Pointer to buffer that will accept output string.
  966. cchDest [in] Size of pszDest, in chars
  967. pszSrc [in/out] Pointer to source string
  968. Warning: This function changes pszSrc.
  969. Return Value:
  970. Success / Error in HRESULT form
  971. --*/
  972. HRESULT Class2CopyID(LPSTR pszDest, size_t cchDest, LPSTR pszSrc)
  973. {
  974. int iFirst;
  975. int iLast;
  976. for (iFirst=0; pszSrc[iFirst]==' '; iFirst++)
  977. ;
  978. for (iLast=strlen(pszSrc)-1; iLast >= iFirst && pszSrc[iLast]==' '; iLast--)
  979. ;
  980. pszSrc[iLast+1] = '\0';
  981. return StringCchCopy(pszDest, cchDest, &(pszSrc[iFirst]));
  982. }
  983. BOOL Class2ResponseAction(PThrdGlbl pTG, LPPCB lpPcb)
  984. {
  985. USHORT count;
  986. BOOL fFoundDIS_DCS;
  987. HRESULT hr;
  988. DEBUG_FUNCTION_NAME("Class2ResponseAction");
  989. fFoundDIS_DCS = FALSE;
  990. _fmemset(lpPcb, 0, sizeof(PCB));
  991. // Even though Class2iModemDialog calls Class2XParse, we need to call
  992. // it again, because main function may change pTG->lpbResponseBuf2.
  993. if (pTG->ModemClass == MODEM_CLASS2)
  994. {
  995. Class2Parse(pTG, &pTG->class2_commands, pTG->lpbResponseBuf2 );
  996. }
  997. else
  998. {
  999. Class20Parse(pTG, &pTG->class2_commands, pTG->lpbResponseBuf2 );
  1000. }
  1001. DebugPrintEx( DEBUG_MSG,
  1002. "Number of commands is %d",
  1003. pTG->class2_commands.comm_count);
  1004. for (count=0; count < pTG->class2_commands.comm_count; ++count)
  1005. {
  1006. switch (pTG->class2_commands.command[count])
  1007. {
  1008. case CL2DCE_FDIS:
  1009. case CL2DCE_FDCS:
  1010. DebugPrintEx(DEBUG_MSG,"Found DCS or DIS");
  1011. fFoundDIS_DCS = TRUE;
  1012. // Assign resolution.
  1013. if( pTG->class2_commands.parameters[count][0] == 0)
  1014. {
  1015. lpPcb->Resolution = AWRES_mm080_038;
  1016. DebugPrintEx(DEBUG_MSG,"Normal resolution");
  1017. }
  1018. else if (pTG->class2_commands.parameters[count][0] & 1 )
  1019. {
  1020. // Resolution when reported by a DIS frame indicates
  1021. // it accepts either fine or normal. When reported
  1022. // in a DCS, it means the negotiated value is FINE.
  1023. if (pTG->class2_commands.command[count] == CL2DCE_FDIS)
  1024. {
  1025. // we received a DIS
  1026. lpPcb->Resolution = AWRES_mm080_038 | AWRES_mm080_077;
  1027. DebugPrintEx(DEBUG_MSG,"Normal & Fine resolution");
  1028. }
  1029. else
  1030. {
  1031. // we received a DCS
  1032. lpPcb->Resolution = AWRES_mm080_077;
  1033. DebugPrintEx(DEBUG_MSG,"Fine resolution");
  1034. }
  1035. }
  1036. else
  1037. {
  1038. DebugPrintEx(DEBUG_MSG,"Fall through - Fine resolution");
  1039. lpPcb->Resolution = AWRES_mm080_077;
  1040. }
  1041. // Assign encoding scheme.
  1042. if( pTG->class2_commands.parameters[count][4] == 0)
  1043. {
  1044. lpPcb->Encoding = MH_DATA;
  1045. DebugPrintEx(DEBUG_MSG,"MH Encoding");
  1046. }
  1047. else if ((pTG->class2_commands.parameters[count][4] == 1) ||
  1048. (pTG->class2_commands.parameters[count][4] == 2) ||
  1049. (pTG->class2_commands.parameters[count][4] == 3) )
  1050. {
  1051. lpPcb->Encoding = MH_DATA | MR_DATA;
  1052. DebugPrintEx(DEBUG_MSG,"MR Encoding");
  1053. }
  1054. else
  1055. {
  1056. DebugPrintEx(DEBUG_ERR,"Failed to assign encoding");
  1057. return FALSE;
  1058. }
  1059. // Assign page width.
  1060. if( pTG->class2_commands.parameters[count][2] == 0)
  1061. {
  1062. lpPcb->PageWidth = WIDTH_A4;
  1063. DebugPrintEx(DEBUG_MSG,"A4 Width");
  1064. }
  1065. else if (pTG->class2_commands.parameters[count][2] == 1)
  1066. {
  1067. lpPcb->PageWidth = WIDTH_B4;
  1068. DebugPrintEx(DEBUG_MSG,"B4 Width");
  1069. }
  1070. else if (pTG->class2_commands.parameters[count][2] == 2)
  1071. {
  1072. lpPcb->PageWidth = WIDTH_A3;
  1073. DebugPrintEx(DEBUG_MSG,"A3 Width");
  1074. }
  1075. // We don't support 3 and 4 (A5, A6)
  1076. // but we'll still allow them and map them to A4
  1077. // This is for Elliot bug #1252 - it should have
  1078. // no deleterious effect, since this width field
  1079. // is not used for anything at the point in where
  1080. // bug 1252 occurs. FrankFi
  1081. else if (pTG->class2_commands.parameters[count][2] == 3)
  1082. {
  1083. lpPcb->PageWidth = WIDTH_A4;
  1084. DebugPrintEx(DEBUG_MSG,"A4 Width - we don't support A5");
  1085. }
  1086. else if (pTG->class2_commands.parameters[count][2] == 4)
  1087. {
  1088. lpPcb->PageWidth = WIDTH_A4;
  1089. DebugPrintEx(DEBUG_MSG,"A4 Width - we don't support A6");
  1090. }
  1091. else
  1092. {
  1093. DebugPrintEx(DEBUG_ERR,"Failed to assign width");
  1094. return FALSE;
  1095. }
  1096. // Assign page length.
  1097. if( pTG->class2_commands.parameters[count][3] == 0)
  1098. {
  1099. lpPcb->PageLength = LENGTH_A4;
  1100. DebugPrintEx(DEBUG_MSG,"A4 Length");
  1101. }
  1102. else if (pTG->class2_commands.parameters[count][3] == 1)
  1103. {
  1104. lpPcb->PageLength = LENGTH_B4;
  1105. DebugPrintEx(DEBUG_MSG,"B4 Length");
  1106. }
  1107. else if (pTG->class2_commands.parameters[count][3] == 2)
  1108. {
  1109. lpPcb->PageLength = LENGTH_UNLIMITED;
  1110. DebugPrintEx(DEBUG_MSG,"Unlimited Length");
  1111. }
  1112. else
  1113. {
  1114. DebugPrintEx(DEBUG_ERR,"Invalid length");
  1115. // assume it is unlimited! Some modems
  1116. // screw up on length.
  1117. lpPcb->PageLength = LENGTH_UNLIMITED;
  1118. }
  1119. // Assign baud rate
  1120. // For now, we will use the raw numbers returned in the
  1121. // DCS command. Dangerous - should fix later!
  1122. // These numbers will be tied to the baud rate array in
  1123. // the routine that figures out zero byte stuffing from
  1124. // the scan line and baud rate.
  1125. // Fixed the Hack--added a Baud field
  1126. lpPcb->Baud = pTG->class2_commands.parameters[count][1];
  1127. if (lpPcb->Baud > CLASS2_MAX_CODE_TO_BPS)
  1128. {
  1129. DebugPrintEx(DEBUG_WRN, "Invalid baud rate %d, will be regarded as %d",
  1130. lpPcb->Baud, CLASS2_MAX_CODE_TO_BPS);
  1131. lpPcb->Baud = CLASS2_MAX_CODE_TO_BPS;
  1132. }
  1133. // Assign minimum scan time - the first number
  1134. // in the MINSCAN_num_num_num constant
  1135. // refers to scan time in ms for 100dpi, the
  1136. // second for 200dpi, and the last for 400dpi
  1137. // Class 2 does not use the 400dpi number,
  1138. // but these variables are shared with Class 1
  1139. if( pTG->class2_commands.parameters[count][7] == 0)
  1140. {
  1141. lpPcb->MinScan = MINSCAN_0_0_0;
  1142. }
  1143. else if (pTG->class2_commands.parameters[count][7] == 1)
  1144. {
  1145. lpPcb->MinScan = MINSCAN_5_5_5;
  1146. }
  1147. else if (pTG->class2_commands.parameters[count][7] == 2)
  1148. {
  1149. lpPcb->MinScan = MINSCAN_10_5_5;
  1150. }
  1151. else if (pTG->class2_commands.parameters[count][7] == 3)
  1152. {
  1153. lpPcb->MinScan = MINSCAN_10_10_10;
  1154. }
  1155. else if (pTG->class2_commands.parameters[count][7] == 4)
  1156. {
  1157. lpPcb->MinScan = MINSCAN_20_10_10;
  1158. }
  1159. else if (pTG->class2_commands.parameters[count][7] == 5)
  1160. {
  1161. lpPcb->MinScan = MINSCAN_20_20_20;
  1162. }
  1163. else if (pTG->class2_commands.parameters[count][7] == 6)
  1164. {
  1165. lpPcb->MinScan = MINSCAN_40_20_20;
  1166. }
  1167. else if (pTG->class2_commands.parameters[count][7] == 7)
  1168. {
  1169. lpPcb->MinScan = MINSCAN_40_40_40;
  1170. }
  1171. break;
  1172. case CL2DCE_FCSI:
  1173. case CL2DCE_FTSI:
  1174. hr = Class2CopyID(lpPcb->szID, ARR_SIZE(lpPcb->szID), pTG->class2_commands.parameters[count]);
  1175. if (FAILED(hr))
  1176. {
  1177. DebugPrintEx(DEBUG_WRN,"Class2CopyID failed (ec=0x%08X)",hr);
  1178. }
  1179. // prepare CSID for logging by FaxSvc
  1180. pTG->RemoteID = AnsiStringToUnicodeString(lpPcb->szID);
  1181. if (pTG->RemoteID)
  1182. {
  1183. pTG->fRemoteIdAvail = 1;
  1184. }
  1185. break;
  1186. default:
  1187. break;
  1188. }
  1189. }
  1190. return fFoundDIS_DCS;
  1191. }
  1192. USHORT Class2EndPageResponseAction(PThrdGlbl pTG)
  1193. {
  1194. USHORT csi_count = 0,count;
  1195. DEBUG_FUNCTION_NAME("Class2EndPageResponseAction");
  1196. for(count=0; count < pTG->class2_commands.comm_count; ++count)
  1197. {
  1198. switch (pTG->class2_commands.command[count])
  1199. {
  1200. case CL2DCE_FET:
  1201. switch (pTG->class2_commands.parameters[count][0])
  1202. {
  1203. case 0: PSSLogEntry(PSS_MSG, 1, "Received MPS");
  1204. DebugPrintEx(DEBUG_MSG,"More pages coming");
  1205. return MORE_PAGES;
  1206. case 1: PSSLogEntry(PSS_MSG, 1, "Received EOM");
  1207. DebugPrintEx(DEBUG_MSG,"More pages coming");
  1208. return MORE_PAGES;
  1209. case 2: PSSLogEntry(PSS_MSG, 1, "Received EOP");
  1210. DebugPrintEx(DEBUG_MSG,"No more pages coming");
  1211. return NO_MORE_PAGES;
  1212. default: PSSLogEntry(PSS_MSG, 1, "Received unknown response");
  1213. DebugPrintEx(DEBUG_MSG,"No more pages coming");
  1214. return NO_MORE_PAGES;
  1215. }
  1216. break;
  1217. case CL2DCE_FPTS:
  1218. pTG->FPTSreport = pTG->class2_commands.parameters[count][0];
  1219. DebugPrintEx(DEBUG_MSG, "FPTS returned %d", pTG->FPTSreport);
  1220. break;
  1221. }
  1222. }
  1223. return FALSE;
  1224. }
  1225. extern DWORD PageWidthInPixelsFromDCS[];
  1226. /*++
  1227. Routine Description:
  1228. Update pTG->TiffInfo according to lpPcb.
  1229. Arguments:
  1230. lpPcb - last received DCS, in PCB format
  1231. Return Value:
  1232. TRUE for success, FALSE for failure.
  1233. --*/
  1234. BOOL Class2UpdateTiffInfo(PThrdGlbl pTG, LPPCB lpPcb)
  1235. {
  1236. DEBUG_FUNCTION_NAME("Class2UpdateTiffInfo");
  1237. if (!lpPcb)
  1238. {
  1239. DebugPrintEx(DEBUG_WRN, "lpPcb==NULL");
  1240. return FALSE;
  1241. }
  1242. if (lpPcb->PageWidth >= 4) // PageWidthInPixelsFromDCS has 4 entries
  1243. {
  1244. DebugPrintEx(DEBUG_WRN, "Unsupported PageWidth %d", lpPcb->PageWidth);
  1245. return FALSE;
  1246. }
  1247. pTG->TiffInfo.ImageWidth = PageWidthInPixelsFromDCS[lpPcb->PageWidth];
  1248. pTG->TiffInfo.YResolution = (lpPcb->Resolution & (AWRES_mm080_077 | AWRES_200_200)) ?
  1249. TIFFF_RES_Y : TIFFF_RES_Y_DRAFT;
  1250. pTG->TiffInfo.CompressionType = (lpPcb->Encoding & MR_DATA) ? TIFF_COMPRESSION_MR : TIFF_COMPRESSION_MH;
  1251. return TRUE;
  1252. }
  1253. /*++
  1254. Routine Description:
  1255. Checks whether received DCS (in PCB format) is valid. Currently, only verifies width
  1256. Arguments:
  1257. lpPcb - last received DCS, in PCB format
  1258. Return Value:
  1259. TRUE for valid, FALSE for invalid.
  1260. --*/
  1261. BOOL Class2IsValidDCS(LPPCB lpPcb)
  1262. {
  1263. DEBUG_FUNCTION_NAME("Class2IsValidDCS");
  1264. if (!lpPcb)
  1265. {
  1266. DebugPrintEx(DEBUG_WRN, "lpPcb==NULL");
  1267. return FALSE;
  1268. }
  1269. if (lpPcb->PageWidth != WIDTH_A4) // We currently support only A4
  1270. {
  1271. DebugPrintEx(DEBUG_WRN, "Unsupported PageWidth %d", lpPcb->PageWidth);
  1272. return FALSE;
  1273. }
  1274. return TRUE;
  1275. }
  1276. void Class2InitBC(PThrdGlbl pTG, LPBC lpbc, USHORT uSize, BCTYPE bctype)
  1277. {
  1278. _fmemset(lpbc, 0, uSize);
  1279. lpbc->bctype = bctype;
  1280. lpbc->wBCSize = sizeof(BC);
  1281. lpbc->wTotalSize = sizeof(BC);
  1282. /**
  1283. lpbc->Fax.AwRes = (AWRES_mm080_038 | AWRES_mm080_077 | AWRES_200_200 | AWRES_300_300);
  1284. lpbc->Fax.Encoding = MH_DATA; // ENCODE_ALL eventually!
  1285. lpbc->Fax.PageWidth = WIDTH_A4;
  1286. lpbc->Fax.PageLength = LENGTH_UNLIMITED;
  1287. lpbc->Fax.MinScan = MINSCAN_0_0_0;
  1288. **/
  1289. }
  1290. void Class2PCBtoBC(PThrdGlbl pTG, LPBC lpbc, USHORT uMaxSize, LPPCB lppcb)
  1291. {
  1292. lpbc->Fax.AwRes = lppcb->Resolution;
  1293. lpbc->Fax.Encoding = lppcb->Encoding;
  1294. lpbc->Fax.PageWidth = lppcb->PageWidth;
  1295. lpbc->Fax.PageLength = lppcb->PageLength;
  1296. }
  1297. BOOL Class2GetBC(PThrdGlbl pTG, BCTYPE bctype)
  1298. {
  1299. USHORT uLen;
  1300. LPBC lpbc;
  1301. DEBUG_FUNCTION_NAME("Class2GetBC");
  1302. if(bctype == BC_NONE)
  1303. {
  1304. DebugPrintEx(DEBUG_MSG,"entering, type = BC_NONE");
  1305. Class2InitBC(pTG, (LPBC)&pTG->bcSendCaps, sizeof(pTG->bcSendCaps), SEND_CAPS);
  1306. pTG->bcSendCaps.Fax.AwRes = (AWRES_mm080_038 | AWRES_mm080_077);
  1307. pTG->bcSendCaps.Fax.Encoding = MH_DATA;
  1308. pTG->bcSendCaps.Fax.PageWidth = WIDTH_A4;
  1309. pTG->bcSendCaps.Fax.PageLength = LENGTH_UNLIMITED;
  1310. return TRUE;
  1311. }
  1312. if(!(lpbc = ICommGetBC(pTG, bctype)))
  1313. {
  1314. return FALSE;
  1315. }
  1316. DebugPrintEx(DEBUG_MSG, "Class2GetBC: entering, type = %d\n\r", bctype);
  1317. DebugPrintEx(DEBUG_MSG, "Some params: encoding = %d, res = %d\n\r", lpbc->Fax.Encoding, lpbc->Fax.AwRes);
  1318. // Depending on the type, pick the correct global BC structure
  1319. if (bctype == SEND_CAPS)
  1320. {
  1321. uLen = min(sizeof(pTG->bcSendCaps), lpbc->wTotalSize);
  1322. _fmemcpy(&pTG->bcSendCaps, lpbc, uLen);
  1323. return TRUE;
  1324. }
  1325. else if (bctype == SEND_PARAMS)
  1326. {
  1327. uLen = min(sizeof(pTG->bcSendParams), lpbc->wTotalSize);
  1328. _fmemcpy(&pTG->bcSendParams, lpbc, uLen);
  1329. return TRUE;
  1330. }
  1331. else
  1332. {
  1333. return FALSE;
  1334. }
  1335. }
  1336. BOOL Class2SetProtParams(PThrdGlbl pTG, LPPROTPARAMS lp)
  1337. {
  1338. DEBUG_FUNCTION_NAME("Class2SetProtParams");
  1339. pTG->ProtParams2 = *lp;
  1340. DebugPrintEx( DEBUG_MSG,
  1341. "Set Class2ProtParams: fV17Send=%d fV17Recv=%d uMinScan=%d",
  1342. " HighestSend=%d LowestSend=%d",
  1343. pTG->ProtParams2.fEnableV17Send,
  1344. pTG->ProtParams2.fEnableV17Recv,
  1345. pTG->ProtParams2.uMinScan,
  1346. pTG->ProtParams2.HighestSendSpeed,
  1347. pTG->ProtParams2.LowestSendSpeed);
  1348. return TRUE;
  1349. }
  1350. void iNCUParamsReset(PThrdGlbl pTG)
  1351. {
  1352. _fmemset(&pTG->NCUParams2, 0, sizeof(pTG->NCUParams2));
  1353. pTG->lpCmdTab = 0;
  1354. pTG->NCUParams2.uSize = sizeof(pTG->NCUParams2);
  1355. // These are used to set S regs etc.
  1356. // -1 means leave modem at default
  1357. pTG->NCUParams2.DialPauseTime = -1;
  1358. // pTG->NCUParams2.PulseMakeBreak = pTG->NCUParams2.DialBlind = -1;
  1359. pTG->NCUParams2.DialBlind = -1;
  1360. pTG->NCUParams2.SpeakerVolume = pTG->NCUParams2.SpeakerControl = -1;
  1361. pTG->NCUParams2.SpeakerRing = -1;
  1362. // used in Dial
  1363. pTG->NCUParams2.chDialModifier = 'T';
  1364. }
  1365. BYTE rgbFlip256[256] = {
  1366. 0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
  1367. 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
  1368. 0x8, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
  1369. 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
  1370. 0x4, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
  1371. 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
  1372. 0xc, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
  1373. 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
  1374. 0x2, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
  1375. 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
  1376. 0xa, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
  1377. 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
  1378. 0x6, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
  1379. 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
  1380. 0xe, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
  1381. 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
  1382. 0x1, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
  1383. 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
  1384. 0x9, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
  1385. 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
  1386. 0x5, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
  1387. 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
  1388. 0xd, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
  1389. 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
  1390. 0x3, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
  1391. 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
  1392. 0xb, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
  1393. 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
  1394. 0x7, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
  1395. 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
  1396. 0xf, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
  1397. 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
  1398. };
  1399. #define FLIP(index) (lpb[(index)] = rgbFlip256[lpb[(index)]])
  1400. void cl2_flip_bytes(LPB lpb, DWORD dw)
  1401. {
  1402. while (dw>8)
  1403. {
  1404. FLIP(0); FLIP(1); FLIP(2); FLIP(3);
  1405. FLIP(4); FLIP(5); FLIP(6); FLIP(7);
  1406. dw-=8;
  1407. lpb+=8;
  1408. }
  1409. while(dw)
  1410. {
  1411. FLIP(0);
  1412. dw--;
  1413. lpb++;
  1414. }
  1415. }
  1416. // These values are taken from table 20/T.32: "Hangup status codes"
  1417. #define FHNG_DCS_NO_RESPONSE 25
  1418. #define FHNG_FAIL_TRAIN_AT_LOWEST_SPEED 27
  1419. #define FHNG_MPS_NO_RESPONSE 52
  1420. #define FHNG_EOP_NO_RESPONSE 54
  1421. #define FHNG_EOM_NO_RESPONSE 56
  1422. /*++
  1423. Routine Description:
  1424. Calls SignalStatusChange with the appropriate StatusId and StringId, according
  1425. to dwFHNGReason.
  1426. --*/
  1427. void Class2SignalFatalError(PThrdGlbl pTG)
  1428. {
  1429. DEBUG_FUNCTION_NAME("Class2ReportFatalError");
  1430. if (pTG->fFatalErrorWasSignaled)
  1431. {
  1432. return;
  1433. }
  1434. pTG->fFatalErrorWasSignaled = TRUE;
  1435. if (pTG->fFoundFHNG)
  1436. {
  1437. switch (pTG->dwFHNGReason)
  1438. {
  1439. case FHNG_DCS_NO_RESPONSE:
  1440. SignalStatusChangeWithStringId(pTG, FS_NO_RESPONSE, IDS_NO_RESPONSE);
  1441. break;
  1442. case FHNG_FAIL_TRAIN_AT_LOWEST_SPEED:
  1443. if (pTG->Operation==T30_TX)
  1444. {
  1445. SignalStatusChangeWithStringId(pTG, FS_SEND_BAD_TRAINING, IDS_SEND_BAD_TRAINING);
  1446. }
  1447. else
  1448. {
  1449. SignalStatusChangeWithStringId(pTG, FS_RECV_BAD_TRAINING, IDS_RECV_BAD_TRAINING);
  1450. }
  1451. break;
  1452. case FHNG_MPS_NO_RESPONSE:
  1453. case FHNG_EOP_NO_RESPONSE:
  1454. case FHNG_EOM_NO_RESPONSE:
  1455. SignalStatusChangeWithStringId(pTG, FS_NO_RESPONSE, IDS_NO_RESPONSE);
  1456. break;
  1457. default: SignalStatusChange(pTG, FS_FATAL_ERROR);
  1458. }
  1459. }
  1460. else
  1461. {
  1462. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1463. }
  1464. }