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.

962 lines
33 KiB

  1. /***************************************************************************
  2. Name : DDI.C
  3. Copyright (c) Microsoft Corp. 1991 1992 1993
  4. Revision Log
  5. Num Date Name Description
  6. --- -------- ---------- -----------------------------------------------
  7. ***************************************************************************/
  8. #define USE_DEBUG_CONTEXT DEBUG_CONTEXT_T30_CLASS1
  9. #include "prep.h"
  10. #include "mmsystem.h"
  11. #include "comdevi.h"
  12. #include "class1.h"
  13. ///RSL
  14. #include "glbproto.h"
  15. #include "psslog.h"
  16. #define FILE_ID FILE_ID_DDI
  17. /* Converts a the T30 code for a speed to the Class1 code
  18. * Generates V.17 with Long Training.
  19. * Add 1 to V.17 codes to get teh Short-train version
  20. */
  21. BYTE T30toC1[16] =
  22. {
  23. /* V27_2400 0 */ 24,
  24. /* V29_9600 1 */ 96,
  25. /* V27_4800 2 */ 48,
  26. /* V29_7200 3 */ 72,
  27. /* V33_14400 4 */ 145, // 144, // V33==V17_long_train FTM=144 is illegal
  28. 0,
  29. /* V33_12000 6 */ 121, // 120, // V33==V17_long_train FTM=120 is illegal
  30. /* V21 squeezed in */ 3,
  31. /* V17_14400 8 */ 145,
  32. /* V17_9600 9 */ 97,
  33. /* V17_12000 10 */ 121,
  34. /* V17_7200 11 */ 73,
  35. 0,
  36. 0,
  37. 0,
  38. 0
  39. };
  40. CBSZ cbszFTH3 = "AT+FTH=3\r";
  41. CBSZ cbszFRH3 = "AT+FRH=3\r";
  42. CBSZ cbszFTM = "AT+FTM=%d\r";
  43. CBSZ cbszFRM = "AT+FRM=%d\r";
  44. // echo off, verbose response, no auto answer, hangup on DTR drop
  45. // 30 seconds timer on connect, speaker always off, speaker volume=0
  46. // busy&dialtone detect enabled
  47. extern CBSZ cbszOK ;
  48. extern CBSZ cbszCONNECT ;
  49. extern CBSZ cbszNOCARRIER ;
  50. extern CBSZ cbszERROR ;
  51. extern CBSZ cbszFCERROR ;
  52. #define ST_MASK (0x8 | ST_FLAG) // 8 selects V17 only. 16 selects ST flag
  53. /******************** Global Vars *********/
  54. BYTE bDLEETX[3] = { DLE, ETX, 0 };
  55. BYTE bDLEETXOK[9] = { DLE, ETX, '\r', '\n', 'O', 'K', '\r', '\n', 0 };
  56. /******************** Global Vars *********/
  57. USHORT NCUDial(PThrdGlbl pTG, LPSTR szPhoneNum)
  58. {
  59. USHORT uRet;
  60. _fmemset(&pTG->Class1Modem, 0, sizeof(CLASS1_MODEM));
  61. if((uRet = iModemDial(pTG, szPhoneNum)) == CONNECT_OK)
  62. {
  63. pTG->Class1Modem.ModemMode = FRH;
  64. }
  65. return uRet;
  66. }
  67. USHORT NCULink
  68. (
  69. PThrdGlbl pTG,
  70. USHORT uFlags
  71. )
  72. {
  73. USHORT uRet;
  74. DEBUG_FUNCTION_NAME(_T("NCULink"));
  75. switch(uFlags)
  76. {
  77. case NCULINK_HANGUP:
  78. if(iModemHangup(pTG))
  79. {
  80. uRet = CONNECT_OK;
  81. }
  82. else
  83. {
  84. uRet = CONNECT_ERROR;
  85. }
  86. break;
  87. case NCULINK_RX:
  88. _fmemset(&pTG->Class1Modem, 0, sizeof(CLASS1_MODEM));
  89. if((uRet = iModemAnswer(pTG)) == CONNECT_OK)
  90. {
  91. pTG->Class1Modem.ModemMode = FTH;
  92. }
  93. break;
  94. default: uRet = CONNECT_ERROR;
  95. break;
  96. }
  97. DebugPrintEx( DEBUG_MSG, "uRet=%d", uRet);
  98. return uRet;
  99. }
  100. // dangerous. May get 2 OKs, may get one. Generally avoid
  101. // CBSZ cbszATAT = "AT\rAT\r";
  102. CBSZ cbszAT1 = "AT\r";
  103. BOOL iModemSyncEx(PThrdGlbl pTG, ULONG ulTimeout, DWORD dwFlags)
  104. {
  105. DEBUG_FUNCTION_NAME(("iModemSyncEx"));
  106. ///// Do cleanup of global state //////
  107. FComOutFilterClose(pTG);
  108. FComOverlappedIO(pTG, FALSE);
  109. FComXon(pTG, FALSE);
  110. EndMode(pTG);
  111. ///// Do cleanup of global state //////
  112. {
  113. LPCMDTAB lpCmdTab = iModemGetCmdTabPtr(pTG);
  114. if ( (dwFlags & fMDMSYNC_DCN) &&
  115. (pTG->Class1Modem.ModemMode == COMMAND) &&
  116. lpCmdTab &&
  117. (lpCmdTab->dwFlags&fMDMSP_C1_NO_SYNC_IF_CMD)
  118. )
  119. {
  120. DebugPrintEx(DEBUG_WRN, "NOT Syching modem (MSPEC)");
  121. Sleep(100); // +++ 4/12 JosephJ -- try to elim this -- it's juse
  122. // that we used to always issue an AT here, which
  123. // we now don't, so I issue a 100ms delay here instead.
  124. // MOST probably unnessary. The AT was issued by
  125. // accident on 4/94 -- as a side effect of
  126. // a change in T.30 code -- when iModemSyncEx was
  127. // called just before a normal dosconnect. Unfortunately
  128. // we discovered in 4/95, 2 weeks before code freeze,
  129. // that the AT&T DataPort express (TT14), didn't
  130. // like this AT.
  131. return TRUE;
  132. }
  133. else
  134. {
  135. return (iModemPauseDialog(pTG, (LPSTR)cbszAT1, sizeof(cbszAT1)-1, ulTimeout, cbszOK)==1);
  136. }
  137. }
  138. }
  139. // length of TCF = 1.5 * bpscode * 100 / 8 == 75 * bpscode / 4
  140. USHORT TCFLen[16] =
  141. {
  142. /* V27_2400 0 */ 450,
  143. /* V29_9600 1 */ 1800,
  144. /* V27_4800 2 */ 900,
  145. /* V29_7200 3 */ 1350,
  146. /* V33_14400 4 */ 2700,
  147. 0,
  148. /* V33_12000 6 */ 2250,
  149. 0,
  150. /* V17_14400 8 */ 2700,
  151. /* V17_9600 9 */ 1800,
  152. /* V17_12000 10 */ 2250,
  153. /* V17_7200 11 */ 1350,
  154. 0,
  155. 0,
  156. 0,
  157. 0
  158. };
  159. #define min(x,y) (((x) < (y)) ? (x) : (y))
  160. #define ZERO_BUFSIZE 256
  161. void SendZeros1(PThrdGlbl pTG, USHORT uCount)
  162. {
  163. BYTE bZero[ZERO_BUFSIZE];
  164. short i; // must be signed
  165. DEBUG_FUNCTION_NAME(_T("SendZeros1"));
  166. PSSLogEntry(PSS_MSG, 2, "send: %d zeroes", uCount);
  167. _fmemset(bZero, 0, ZERO_BUFSIZE);
  168. for(i=uCount; i>0; i -= ZERO_BUFSIZE)
  169. {
  170. // no need to stuff. They're all zeros!
  171. FComDirectAsyncWrite(pTG, bZero, (UWORD)(min((UWORD)i, (UWORD)ZERO_BUFSIZE)));
  172. }
  173. DebugPrintEx(DEBUG_MSG,"Sent %d zeros",uCount);
  174. }
  175. BOOL ModemSendMode
  176. (
  177. PThrdGlbl pTG,
  178. USHORT uMod
  179. )
  180. {
  181. DEBUG_FUNCTION_NAME(_T("ModemSendMode"));
  182. pTG->Class1Modem.CurMod = T30toC1[uMod & 0xF];
  183. if((uMod & ST_MASK) == ST_MASK) // mask selects V.17 and ST bits
  184. {
  185. pTG->Class1Modem.CurMod++;
  186. }
  187. DebugPrintEx( DEBUG_MSG,
  188. "uMod=%d CurMod=%d",
  189. uMod,
  190. pTG->Class1Modem.CurMod);
  191. if(uMod == V21_300)
  192. {
  193. _fstrcpy(pTG->Class1Modem.bCmdBuf, (LPSTR)cbszFTH3);
  194. pTG->Class1Modem.uCmdLen = sizeof(cbszFTH3)-1;
  195. pTG->Class1Modem.fHDLC = TRUE;
  196. FComXon(pTG, FALSE); // for safety. _May_ be critical
  197. }
  198. else
  199. {
  200. pTG->Class1Modem.uCmdLen = (USHORT)wsprintf(pTG->Class1Modem.bCmdBuf, cbszFTM, pTG->Class1Modem.CurMod);
  201. pTG->Class1Modem.fHDLC = FALSE;
  202. FComXon(pTG, TRUE); // critical!! Start of PhaseC
  203. // no harm doing it here(i.e before issuing +FTM)
  204. }
  205. FComOutFilterInit(pTG); // _not_ used for 300bps HDLC
  206. // but here just in case
  207. // want to do all the work _before_ issuing command
  208. pTG->Class1Modem.DriverMode = SEND;
  209. if(pTG->Class1Modem.ModemMode == FTH)
  210. {
  211. // already in send mode. This happens on Answer only
  212. return TRUE;
  213. }
  214. #define STARTSENDMODE_TIMEOUT 5000 // Random Timeout
  215. //// Try to cut down delay between getting CONNECT and writing the
  216. // first 00s (else modems can quit because of underrun).
  217. // Can do this by not sleeping in this. Only in fatal
  218. // cases will it lock up for too long (max 5secs). In those cases
  219. // the call is trashed too.
  220. if(!iModemNoPauseDialog(pTG, (LPB)pTG->Class1Modem.bCmdBuf, pTG->Class1Modem.uCmdLen, STARTSENDMODE_TIMEOUT, cbszCONNECT))
  221. {
  222. goto error;
  223. }
  224. // can't set this earlier. We'll trash previous value
  225. pTG->Class1Modem.ModemMode = ((uMod==V21_300) ? FTH : FTM);
  226. // Turn OFF overlapped I/O if in V.21 else ON
  227. FComOverlappedIO(pTG, uMod != V21_300);
  228. if(pTG->Class1Modem.ModemMode == FTM)
  229. {
  230. // don't send 00s if ECM
  231. SendZeros1(pTG, (USHORT)(TCFLen[uMod & 0x0F] / PAGE_PREAMBLE_DIV));
  232. }
  233. // FComDrain(-,FALSE) causes fcom to write out any internally-
  234. // maintained buffers, but not to drain the comm-driver buffers.
  235. FComDrain(pTG, TRUE,FALSE);
  236. DebugPrintEx( DEBUG_MSG,
  237. "Starting Send at %d",
  238. pTG->Class1Modem.CurMod);
  239. return TRUE;
  240. error:
  241. FComOutFilterClose(pTG);
  242. FComOverlappedIO(pTG, FALSE);
  243. FComXon(pTG, FALSE); // important. Cleanup on error
  244. EndMode(pTG);
  245. return FALSE;
  246. }
  247. BOOL iModemDrain(PThrdGlbl pTG)
  248. {
  249. DEBUG_FUNCTION_NAME(_T("iModemDrain"));
  250. if(!FComDrain(pTG, TRUE, TRUE))
  251. return FALSE;
  252. // Must turn XON/XOFF off immediately *after* drain, but before we
  253. // send the next AT command, since recieved frames have 0x13 or
  254. // even 0x11 in them!! MUST GO AFTER the getOK ---- See BELOW!!!!
  255. // increase this---see bug number 495. Must be big enough for
  256. // COM_OUTBUFSIZE to safely drain at 2400bps(300bytes/sec = 0.3bytes/ms)
  257. // let's say (COM_OUTBUFSIZE * 10 / 3) == (COM_OUTBUFSIZE * 4)
  258. // can be quite long, because on failure we just barf anyway
  259. #define POSTPAGEOK_TIMEOUT (10000L + (((ULONG)COM_OUTBUFSIZE) << 2))
  260. // Here we were looking for OK only, but some modems (UK Cray Quantun eg)
  261. // give me an ERROR after sending TCF or a page (at speeds < 9600) even
  262. // though the page was sent OK. So we were timing out here. Instead look
  263. // for ERROR (and NO CARRIER too--just in case!), and accept those as OK
  264. // No point returning ERROR from here, since we just abort. We can't/don't
  265. // recover from send errors
  266. if(iModemResp3(pTG, POSTPAGEOK_TIMEOUT, cbszOK, cbszERROR, cbszNOCARRIER) == 0)
  267. return FALSE;
  268. // Must change FlowControl State *after* getting OK because in Windows
  269. // this call takes 500 ms & resets chips, blows away data etc.
  270. // So do this *only* when you *know* both RX & TX are empty.
  271. // check this in all usages of this function
  272. return TRUE;
  273. }
  274. BOOL iModemSendData(PThrdGlbl pTG, LPB lpb, USHORT uCount, USHORT uFlags)
  275. {
  276. DEBUG_FUNCTION_NAME(("iModemSendData"));
  277. {
  278. // always DLE-stuff here. Sometimes zero-stuff
  279. DebugPrintEx(DEBUG_MSG,"calling FComFilterAsyncWrite");
  280. if(!FComFilterAsyncWrite(pTG, lpb, uCount, FILTER_DLEZERO))
  281. goto error;
  282. }
  283. if(uFlags & SEND_FINAL)
  284. {
  285. DebugPrintEx(DEBUG_MSG,"FComDIRECTAsyncWrite");
  286. PSSLogEntry(PSS_MSG, 2, "send: <dle><etx>");
  287. // if(!FComDirectAsyncWrite(bDLEETXCR, 3))
  288. if(!FComDirectAsyncWrite(pTG, bDLEETX, 2))
  289. goto error;
  290. if(!iModemDrain(pTG))
  291. goto error;
  292. FComOutFilterClose(pTG);
  293. FComOverlappedIO(pTG, FALSE);
  294. FComXon(pTG, FALSE); // critical. End of PhaseC
  295. // must come after Drain
  296. EndMode(pTG);
  297. }
  298. return TRUE;
  299. error:
  300. FComXon(pTG, FALSE); // critical. End of PhaseC (error)
  301. FComFlush(pTG); // clean out the buffer if we got an error
  302. FComOutFilterClose(pTG);
  303. FComOverlappedIO(pTG, FALSE);
  304. EndMode(pTG);
  305. return FALSE;
  306. }
  307. BOOL iModemSendFrame(PThrdGlbl pTG, LPB lpb, USHORT uCount, USHORT uFlags)
  308. {
  309. UWORD uwResp=0;
  310. DEBUG_FUNCTION_NAME(("iModemSendFrame"));
  311. // always DLE-stuff here. Never zero-stuff
  312. // This is only called for 300bps HDLC
  313. if(pTG->Class1Modem.ModemMode != FTH) // Special case on just answering!!
  314. {
  315. #define FTH_TIMEOUT 5000 // Random Timeout
  316. if(!iModemNoPauseDialog( pTG,
  317. (LPB)pTG->Class1Modem.bCmdBuf,
  318. pTG->Class1Modem.uCmdLen,
  319. FTH_TIMEOUT,
  320. cbszCONNECT))
  321. goto error;
  322. }
  323. {
  324. // always DLE-stuff here. Never zero-stuff
  325. if(!FComFilterAsyncWrite(pTG, lpb, uCount, FILTER_DLEONLY))
  326. goto error;
  327. }
  328. {
  329. PSSLogEntry(PSS_MSG, 2, "send: <dle><etx>");
  330. if(!FComDirectAsyncWrite(pTG, bDLEETX, 2))
  331. goto error;
  332. }
  333. // 2000 is too short because PPRs can be 32+7 bytes long and
  334. // preamble is 1 sec, so set this to 3000
  335. // 3000 is too short because NSFs and CSIs can be arbitrarily long
  336. // MAXFRAMESIZE is defined in et30type.h. 30ms/byte at 300bps
  337. // async (I think V.21 is syn though), so use N*30+1000+slack
  338. #define WRITEFRAMERESP_TIMEOUT (1000+30*MAXFRAMESIZE+500)
  339. if(!(uwResp = iModemResp2(pTG, WRITEFRAMERESP_TIMEOUT, cbszOK, cbszCONNECT)))
  340. goto error;
  341. pTG->Class1Modem.ModemMode = ((uwResp == 2) ? FTH : COMMAND);
  342. if(uFlags & SEND_FINAL)
  343. {
  344. FComOutFilterClose(pTG);
  345. FComOverlappedIO(pTG, FALSE);
  346. // FComXon(FALSE); // at 300bps. no Xon-Xoff in use
  347. // in some weird cases (Practical Peripherals PM14400FXMT) we get
  348. // CONNECT<cr><lf>OK, but we get the CONNECT here. Should we
  349. // just set pTG->Class1Modem.ModemMode=COMMAND?? (EndMode does that)
  350. // Happens on PP 144FXSA also. Ignore it & just set mode to COMMAND
  351. EndMode(pTG);
  352. }
  353. return TRUE;
  354. error:
  355. FComOutFilterClose(pTG);
  356. FComOverlappedIO(pTG, FALSE);
  357. FComXon(pTG, FALSE); // just for safety. cleanup on error
  358. EndMode(pTG);
  359. return FALSE;
  360. }
  361. BOOL ModemSendMem
  362. (
  363. PThrdGlbl pTG,
  364. LPBYTE lpb,
  365. USHORT uCount,
  366. USHORT uFlags
  367. )
  368. {
  369. DEBUG_FUNCTION_NAME(_T("ModemSendMem"));
  370. DebugPrintEx( DEBUG_MSG,
  371. "lpb=%08lx uCount=%d wFlags=%04x",
  372. lpb,
  373. uCount,
  374. uFlags);
  375. if(pTG->Class1Modem.DriverMode != SEND)
  376. {
  377. return FALSE;
  378. }
  379. if(pTG->Class1Modem.fHDLC)
  380. {
  381. DebugPrintEx(DEBUG_MSG,"(fHDLC) calling: iModemSendFrame");
  382. return iModemSendFrame(pTG, lpb, uCount, uFlags);
  383. }
  384. else
  385. {
  386. DebugPrintEx(DEBUG_MSG,"(Else) calling: iModemSendData");
  387. return iModemSendData(pTG, lpb, uCount, uFlags);
  388. }
  389. }
  390. #define MINRECVMODETIMEOUT 500
  391. #define RECVMODEPAUSE 200
  392. USHORT ModemRecvMode(PThrdGlbl pTG, USHORT uMod, ULONG ulTimeout, BOOL fRetryOnFCERROR)
  393. {
  394. USHORT uRet;
  395. ULONG ulBefore, ulAfter;
  396. DEBUG_FUNCTION_NAME(_T("ModemRecvMode"));
  397. // Here we should watch for a different modulation scheme from what we expect.
  398. // Modems are supposed to return a +FCERROR code to indicate this condition,
  399. // but I have not seen it from any modem yet, so we just scan for ERROR
  400. // (this will catch +FCERROR too since iiModemDialog does not expect whole
  401. // words or anything silly like that!), and treat both the same.
  402. pTG->Class1Modem.CurMod = T30toC1[uMod & 0xF];
  403. if((uMod & ST_MASK) == ST_MASK) // mask selects V.17 and ST bits
  404. {
  405. pTG->Class1Modem.CurMod++;
  406. }
  407. if(uMod == V21_300)
  408. {
  409. _fstrcpy(pTG->Class1Modem.bCmdBuf, (LPSTR)cbszFRH3);
  410. pTG->Class1Modem.uCmdLen = sizeof(cbszFRH3)-1;
  411. }
  412. else
  413. {
  414. pTG->Class1Modem.uCmdLen = (USHORT)wsprintf(pTG->Class1Modem.bCmdBuf, cbszFRM, pTG->Class1Modem.CurMod);
  415. }
  416. if(pTG->Class1Modem.ModemMode == FRH)
  417. {
  418. // already in receive mode. This happens upon Dial only
  419. pTG->Class1Modem.fHDLC = TRUE;
  420. pTG->Class1Modem.DriverMode = RECV;
  421. FComInFilterInit(pTG);
  422. return RECV_OK;
  423. }
  424. // On Win32, we have a problem going into 2400baud recv.
  425. // +++ remember to put this into iModemFRHorM when that code is enabled.
  426. if (pTG->Class1Modem.CurMod==24) Sleep(80);
  427. retry:
  428. ulBefore=GetTickCount();
  429. // Don't look for NO CARRIER. Want it to retry until FRM timeout on NO CARRIER
  430. // ----This is changed. See below----
  431. uRet = iModemNoPauseDialog3(pTG, pTG->Class1Modem.bCmdBuf, pTG->Class1Modem.uCmdLen, ulTimeout, cbszCONNECT, cbszFCERROR, cbszNOCARRIER);
  432. // uRet = iModemNoPauseDialog2(pTG->Class1Modem.bCmdBuf, pTG->Class1Modem.uCmdLen, ulTimeout, cbszCONNECT, cbszFCERROR);
  433. ulAfter=GetTickCount();
  434. if((fRetryOnFCERROR && uRet==2) || uRet==3) // uRet==FCERROR or uRet==NOCARRIER
  435. {
  436. if( (ulAfter <= ulBefore) || // wraparound or 0 time elapsed (timer broke)
  437. (ulTimeout < ((ulAfter-ulBefore) + MINRECVMODETIMEOUT)))
  438. {
  439. DebugPrintEx( DEBUG_WRN,
  440. "Giving up on RecvMode. uRet=%d ulTimeout=%ld",
  441. uRet,
  442. ulTimeout);
  443. }
  444. else
  445. {
  446. ulTimeout -= (ulAfter-ulBefore);
  447. // need this pause for NO CARRIER for USR modems. See bug#1516
  448. // for the RC229DP, dunno if it's reqd because I dunno why theyre
  449. // giving the FCERROR. Don't want to miss the carrier so currently
  450. // don't pause. (Maybe we can achieve same effect by simply taking
  451. // FCERROR out of the response list above--but that won't work for
  452. // NOCARRIER because we _need_ teh pause. iiModemDialog is too fast)
  453. if(uRet == 3)
  454. Sleep(RECVMODEPAUSE);
  455. goto retry;
  456. }
  457. }
  458. DebugPrintEx( DEBUG_MSG,
  459. "uMod=%d CurMod=%dulTimeout=%ld: Got=%d",
  460. uMod,
  461. pTG->Class1Modem.CurMod,
  462. ulTimeout,
  463. uRet);
  464. if(uRet != 1)
  465. {
  466. EndMode(pTG);
  467. if(uRet == 2)
  468. {
  469. DebugPrintEx( DEBUG_WRN,
  470. "Got FCERROR after %ldms",
  471. ulAfter-ulBefore);
  472. return RECV_WRONGMODE; // need to return quickly
  473. }
  474. else
  475. {
  476. DebugPrintEx( DEBUG_WRN,
  477. "Got Timeout after %ldms",
  478. ulAfter-ulBefore);
  479. return RECV_TIMEOUT;
  480. }
  481. }
  482. if(uMod==V21_300)
  483. {
  484. pTG->Class1Modem.ModemMode = FRH;
  485. pTG->Class1Modem.fHDLC = TRUE;
  486. }
  487. else
  488. {
  489. pTG->Class1Modem.ModemMode = FRM;
  490. pTG->Class1Modem.fHDLC = FALSE;
  491. }
  492. pTG->Class1Modem.DriverMode = RECV;
  493. FComInFilterInit(pTG);
  494. DebugPrintEx(DEBUG_MSG, "Starting Recv at %d", pTG->Class1Modem.CurMod);
  495. return RECV_OK;
  496. }
  497. USHORT iModemRecvData
  498. (
  499. PThrdGlbl pTG,
  500. LPB lpb,
  501. USHORT cbMax,
  502. ULONG ulTimeout,
  503. USHORT far* lpcbRecv
  504. )
  505. {
  506. SWORD swEOF;
  507. USHORT uRet;
  508. DEBUG_FUNCTION_NAME(("iModemRecvData"));
  509. startTimeOut(pTG, &(pTG->Class1Modem.toRecv), ulTimeout);
  510. // 4th arg must be FALSE for Class1
  511. *lpcbRecv = FComFilterReadBuf(pTG, lpb, cbMax, &(pTG->Class1Modem.toRecv), FALSE, &swEOF);
  512. if(swEOF == -1)
  513. {
  514. // we got a DLE-ETX _not_ followed by OK or NO CARRIER. So now
  515. // we have to decide whether to (a) declare end of page (swEOF=1)
  516. // or (b) ignore it & assume page continues on (swEOF=0).
  517. //
  518. // The problem is that some modems produce spurious EOL during a page
  519. // I believe this happens due a momentary loss of carrier that they
  520. // recover from. For example IFAX sending to the ATI 19200. In those
  521. // cases we want to do (b). The opposite problem is that we'll run
  522. // into a modem whose normal response is other than OK or NO CARRIER.
  523. // Then we want to do (a) because otherwise we'll _never_ work with
  524. // that modem.
  525. //
  526. // So we have to either do (a) always, or have an INI setting that
  527. // can force (a), which could be set thru the AWMODEM.INF file. But
  528. // we also want to do (b) if possible because otehrwise we'll not be
  529. // able to recieve from weak or flaky modems or machines or whatever
  530. //
  531. // Snowball does (b). I believe best soln is an INI setting, with (b)
  532. // as default
  533. // option (a)
  534. // swEOF = 1;
  535. // option (b)
  536. DebugPrintEx(DEBUG_WRN,"Got arbitrary DLE-ETX. Ignoring");
  537. swEOF = 0;
  538. }
  539. switch(swEOF)
  540. {
  541. case 1: uRet = RECV_EOF;
  542. break;
  543. case 0: return RECV_OK;
  544. default: // fall through
  545. case -2: uRet = RECV_ERROR;
  546. break;
  547. case -3: uRet = RECV_TIMEOUT;
  548. break;
  549. }
  550. EndMode(pTG);
  551. return uRet;
  552. }
  553. const static BYTE LFCRETXDLE[4] = { LF, CR, ETX, DLE };
  554. USHORT iModemRecvFrame
  555. (
  556. PThrdGlbl pTG,
  557. LPB lpb,
  558. USHORT cbMax,
  559. ULONG ulTimeout,
  560. USHORT far* lpcbRecv
  561. )
  562. {
  563. SWORD swRead, swRet;
  564. USHORT i;
  565. BOOL fRestarted=0;
  566. USHORT uRet;
  567. BOOL fGotGoodCRC = 0; // see comment-block below
  568. DEBUG_FUNCTION_NAME(_T("iModemRecvFrame"));
  569. /** Sometimes modems give use ERROR even when thr frame is good.
  570. Happens a lot from Thought to PP144MT on CFR. So we check
  571. the CRC. If the CRc was good and everything else looks good
  572. _except_ the "ERROR" response from teh modem then return
  573. RECV_OK, not RECV_BADFRAME.
  574. This should fix BUG#1218
  575. **/
  576. restart:
  577. *lpcbRecv=0;
  578. if(pTG->Class1Modem.ModemMode!= FRH)
  579. {
  580. swRet=iModemNoPauseDialog2(pTG, (LPB)pTG->Class1Modem.bCmdBuf, pTG->Class1Modem.uCmdLen, ulTimeout, cbszCONNECT, cbszNOCARRIER);
  581. if(swRet==2||swRet==3)
  582. {
  583. DebugPrintEx(DEBUG_MSG,"Got NO CARRIER from FRH=3");
  584. EndMode(pTG);
  585. return RECV_EOF;
  586. }
  587. else if(swRet != 1)
  588. {
  589. DebugPrintEx(DEBUG_WRN,"Can't get CONNECT from FRH=3, got %d",swRet);
  590. EndMode(pTG);
  591. return RECV_TIMEOUT; // may not need this, since we never got flags??
  592. // actually we dont know what the heck we got!!
  593. }
  594. }
  595. /*** Got CONNECT (i.e. flags). Now try to get a frame ***/
  596. /****************************************************************
  597. * Using 3 secs here is a misinterpretation of the T30 CommandReceived?
  598. * flowchart. WE want to wait here until we get something or until T2
  599. * or T4 timeout. It would have been best if we started T2 ot T4 on
  600. * entry into the search routine (t30.c), but starting it here is good
  601. * enough.
  602. * Using this 3secs timeout fails when Genoa simulates a bad frame
  603. * because Zoom PKT modem gives us a whole raft of bad frames for one
  604. * bad PPS-EOP and then gives a CONNECT that we timeout below exactly
  605. * as the sender's T4 timeout expires and he re-sends the PPS-EOP
  606. * so we miss all of them.
  607. * Alternately, we could timeout here on 2sec & retry. But that's risky
  608. * If less than 2sec then we'll timeout on modems that give connect
  609. * first flag, then 2sec elapse before CR-LF (1sec preamble & 1sec for
  610. * long frames, e.g. PPR!)
  611. ****************************************************************/
  612. startTimeOut(pTG, &(pTG->Class1Modem.toRecv), ulTimeout);
  613. swRead = FComFilterReadLine(pTG, lpb, cbMax, &(pTG->Class1Modem.toRecv));
  614. pTG->Class1Modem.ModemMode = COMMAND;
  615. // may change this to FRH if we get CONNECT later.
  616. // but set it here just in case we short circuit out due to errors
  617. if(swRead<=0)
  618. {
  619. // Timeout
  620. DebugPrintEx(DEBUG_WRN,"Can't get frame after connect. Got-->%d",(WORD)-swRead);
  621. D_HexPrint(lpb, (WORD)-swRead);
  622. EndMode(pTG);
  623. *lpcbRecv = -swRead;
  624. return RECV_ERROR; // goto error;
  625. }
  626. PSSLogEntryHex(PSS_MSG, 2, lpb, swRead, "recv: HDLC frame, %d bytes,", swRead);
  627. if (pTG->fLineTooLongWasIgnored)
  628. {
  629. // the following case is dealt with here:
  630. // we get an HDLC frame which is longer than 132 bytes, a bad frame.
  631. // the problem is that we might have skipped it and read the 'ERROR'
  632. // after it as the actual data.
  633. // since no HDLC frame can be that long, let's return an error.
  634. // it's important NOT to ask the modem for a response here
  635. // we might have already read it.
  636. DebugPrintEx(DEBUG_WRN,"the received frame was too long, BAD FRAME!", swRead);
  637. (*lpcbRecv) = 0;
  638. uRet = RECV_BADFRAME;
  639. return uRet;
  640. }
  641. if (swRead<10)
  642. {
  643. D_HexPrint(lpb, swRead);
  644. }
  645. for(i=0, swRead--; i<4 && swRead>=0; i++, swRead--)
  646. {
  647. if(lpb[swRead] != LFCRETXDLE[i])
  648. break;
  649. }
  650. // exits when swRead is pointing to last non-noise char
  651. // or swRead == -1
  652. // incr by 1 to give actual non-noise data size.
  653. // (size = ptr to last byte + 1!)
  654. swRead++;
  655. // Hack for AT&T AK144 modem that doesn't send us the CRC
  656. // only lop off last 2 bytes IFF the frame is >= 5 bytes long
  657. // that will leave us at least the FF 03/13 FCF
  658. // if(i==4 && swRead>=2) // i.e. found all of DLE-ETX_CR-LF
  659. // 09/25/95 This code was changed to never lop of the CRC.
  660. // All of the routines except NSxtoBC can figure out the correct length,
  661. // and that way if the modem doesn't pass on the CRC, we no longer
  662. // lop off the data.
  663. // we really want this CRC-checking in the MDDI case too
  664. if(i==4)// i.e. found all of DLE-ETX_CR-LF
  665. {
  666. uRet = RECV_OK;
  667. }
  668. else
  669. {
  670. DebugPrintEx(DEBUG_WRN,"Frame doesn't end in dle-etx-cr-lf");
  671. // leave tast two bytes in. We don't *know* it's a CRC, since
  672. // frame ending was non-standard
  673. uRet = RECV_BADFRAME;
  674. }
  675. *lpcbRecv = swRead;
  676. // check if it is the NULL frame (i.e. DLE-ETX-CR-LF) first.
  677. // (check is: swRead==0 and uRet==RECV_OK (see above))
  678. // if so AND if we get OK or CONNECT or ERROR below then ignore
  679. // it completely. The Thought modem and the PP144MT generate
  680. // this idiotic situation! Keep a flag to avoid a possible
  681. // endless loop
  682. // broaden this so that we Restart on either a dle-etx-cr-lf
  683. // NULL frame or a simple cr-lf NULL frame. But then we need
  684. // to return an ERROR (not BADFRAME) after restarting once,
  685. // otheriwse there is an infinite loop with T30 calling us
  686. // again and again (see bug#834)
  687. // chnage yet again. This takes too long, and were trying to tackle
  688. // a specific bug (the PP144MT) bug here, so let's retsrat only
  689. // on dle-etx-cr-lf (not just cr-lf), and in teh latter case
  690. // return a response according to what we get
  691. /*** Got Frame. Now try to get OK or ERROR. Timeout=0! ***/
  692. switch(swRet = iModemResp4(pTG,0, cbszOK, cbszCONNECT, cbszNOCARRIER, cbszERROR))
  693. {
  694. case 2: pTG->Class1Modem.ModemMode = FRH;
  695. // fall through and do exactly like OK!!
  696. case 1: // ModemMode already == COMMAND
  697. if(swRead<=0 && uRet==RECV_OK && !fRestarted)
  698. {
  699. DebugPrintEx(DEBUG_WRN,"Got %d after frame. RESTARTING", swRet);
  700. fRestarted = 1;
  701. goto restart;
  702. }
  703. //uRet already set
  704. break;
  705. case 3: // NO CARRIER. If got null-frame or no frame return
  706. // RECV_EOF. Otherwise if got OK frame then return RECV_OK
  707. // and return frame as usual. Next time around it'll get a
  708. // NO CARRIER again (hopefully) or timeout. On a bad frame
  709. // we can return RECV_EOF, but this will get into trouble if
  710. // the recv is not actually done. Or return BADFRAME, and hope
  711. // for a NO CARRIER again next time. But next time we may get a
  712. // timeout. ModemMode is always set to COMMAND (already)
  713. DebugPrintEx( DEBUG_WRN,
  714. "Got NO CARRIER after frame. swRead=%d uRet=%d",
  715. swRead,
  716. uRet);
  717. if(swRead <= 0)
  718. uRet = RECV_EOF;
  719. // else uRet is already BADFRAME or OK
  720. break;
  721. // this is bad!!
  722. // alternately:
  723. // if(swRead<=0 || uRet==RECV_BADFRAME)
  724. // {
  725. // uRet = RECV_EOF;
  726. // *lpcbRecv = 0; // must return 0 bytes with RECV_EOF
  727. // }
  728. case 4: // ERROR
  729. if(swRead<=0)
  730. {
  731. // got no frame
  732. if(uRet==RECV_OK && !fRestarted)
  733. {
  734. // if we got dle-etx-cr-lf for first time
  735. DebugPrintEx( DEBUG_WRN,
  736. "Got ERROR after frame. RESTARTING");
  737. fRestarted = 1;
  738. goto restart;
  739. }
  740. else
  741. {
  742. uRet = RECV_ERROR;
  743. }
  744. }
  745. else
  746. {
  747. // if everything was OK until we got the "ERROR" response from
  748. // the modem and we got a good CRC then treat it as "OK"
  749. // This should fix BUG#1218
  750. if(uRet==RECV_OK && fGotGoodCRC)
  751. {
  752. uRet = RECV_OK;
  753. }
  754. else
  755. {
  756. uRet = RECV_BADFRAME;
  757. }
  758. }
  759. DebugPrintEx( DEBUG_WRN,
  760. "Got ERROR after frame. swRead=%d uRet=%d",
  761. swRead,
  762. uRet);
  763. break;
  764. case 0: // timeout
  765. DebugPrintEx( DEBUG_WRN,
  766. "Got TIMEOUT after frame. swRead=%d uRet=%d",
  767. swRead,
  768. uRet);
  769. // if everything was OK until we got the timeout from
  770. // the modem and we got a good CRC then treat it as "OK"
  771. // This should fix BUG#1218
  772. if(uRet==RECV_OK && fGotGoodCRC)
  773. {
  774. uRet = RECV_OK;
  775. }
  776. else
  777. {
  778. uRet = RECV_BADFRAME;
  779. }
  780. break;
  781. }
  782. return uRet;
  783. }
  784. USHORT ModemRecvMem(PThrdGlbl pTG, LPBYTE lpb, USHORT cbMax, ULONG ulTimeout, USHORT far* lpcbRecv)
  785. {
  786. USHORT uRet;
  787. DEBUG_FUNCTION_NAME(_T("ModemRecvMem"));
  788. DebugPrintEx( DEBUG_MSG,
  789. "lpb=%08lx cbMax=%d ulTimeout=%ld",
  790. lpb,
  791. cbMax,
  792. ulTimeout);
  793. if(pTG->Class1Modem.DriverMode != RECV)
  794. {
  795. return RECV_ERROR; // see bug#1492
  796. }
  797. *lpcbRecv=0;
  798. if(pTG->Class1Modem.fHDLC)
  799. {
  800. uRet = iModemRecvFrame(pTG, lpb, cbMax, ulTimeout, lpcbRecv);
  801. }
  802. else
  803. {
  804. uRet = iModemRecvData(pTG, lpb, cbMax, ulTimeout, lpcbRecv);
  805. }
  806. DebugPrintEx( DEBUG_MSG,
  807. "lpbf=%08lx uCount=%d uRet=%d",
  808. lpb,
  809. *lpcbRecv,
  810. uRet);
  811. return uRet;
  812. }