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.

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