Modem.cpp
上传用户:glass0516
上传日期:2010-01-11
资源大小:104k
文件大小:28k
源码类别:

传真(Fax)编程

开发平台:

Visual C++

  1. /*****************************************************************************
  2. * RelayFax Open Source Project
  3. * Copyright 1996-2004 Alt-N Technologies, Ltd.
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted only as authorized by the RelayFax Open 
  8. * Source License.  A copy of this license is available in file LICENSE 
  9. * in the top-level directory of the distribution.
  10. *
  11. * RelayFax is a registered trademark of Alt-N Technologies, Ltd.
  12. *
  13. * Individual files and/or contributed packages may be copyright by
  14. * other parties and subject to additional restrictions.
  15. *****************************************************************************/
  16. ////////////////////////////////////////////////////////////////////////////////
  17. //
  18. // The purpose of CModem build the message loop of an independent thread
  19. // into CCommPort and handle communication with other threads.
  20. //
  21. ////////////////////////////////////////////////////////////////////////////////
  22. #include "stdafx.h"
  23. #include "Modem.h"
  24. char* CModem::s_CommonCmds[COMMAND_COUNT] =
  25. {
  26. "", // COMMAND_NONE, 
  27. "ATZ", // COMMAND_INIT, 
  28. "AT&F&C1&D2S7=55S0=0", // COMMAND_SETUP_STRING
  29. "ATE0", // COMMAND_DISABLE_ECHO, 
  30. "ATL%d", // COMMAND_SET_SPKR_VOL, 
  31. "ATM%d", // COMMAND_SET_SPKR_MODE, 
  32. "AT+FCLASS=1", // COMMAND_SET_FCLASS_1
  33. "AT+FCLASS=1.0", // COMMAND_SET_FCLASS_1_0
  34. "AT+FCLASS=2", // COMMAND_SET_FCLASS_2
  35. "AT+FCLASS=2.0", // COMMAND_SET_FCLASS_2_0
  36. "AT+FCLASS=2.1", // COMMAND_SET_FCLASS_2_1
  37. "AT+FTM=?", // COMMAND_QUERY_SEND_SPEEDS,
  38. "AT+FRM=?", // COMMAND_QUERY_RECEIVE_SPEEDS,
  39. "", // COMMAND_SET_LOCAL_ID,
  40. "", // COMMAND_SET_RECV
  41. "", // COMMAND_SET_BIT_ORDER
  42. "AT+FLO=%d", // COMMAND_SET_FLOW_CONTROL
  43. "", // COMMAND_SET_HDLC_REPORTING
  44. "", // COMMAND_SET_FAX_PARAMS
  45. "ATDT%s", // COMMAND_DIAL
  46. "ATH0", // COMMAND_HANGUP
  47. "ATA", // COMMAND_ANSWER
  48. "AT+FCLASS=?", // COMMAND_QUERY_FCLASS
  49. "ATI0", // COMMAND_QUERY_PRODUCT_CODE
  50. "ATI3", // COMMAND_QUERY_MANUFACTURER
  51. "AT+FDCC=?", // COMMAND_QUERY_CLASS2_CAP
  52. "AT+FMFR?", // COMMAND_QUERY_CLASS2_MANUFACT
  53. "AT+FMDL?", // COMMAND_QUERY_CLASS2_MODEL
  54. "AT+FCC=?", // COMMAND_QUERY_CLASS2_0_CAP
  55. "AT+FMI?", // COMMAND_QUERY_CLASS2_0_MANUFACT
  56. "AT+FMM?", // COMMAND_QUERY_CLASS2_0_MODEL
  57. };
  58. //MODEM_EVENT_HANDLER_FUNC CModem::s_ModemEventHandlerFunc = NULL;
  59. //////////////////////////////////////////////////////////////////////
  60. // Construction/Destruction
  61. //////////////////////////////////////////////////////////////////////
  62. CModem::CModem()
  63. {
  64. m_bConnected = false;
  65. m_sInitString.assign( s_CommonCmds[COMMAND_SETUP_STRING] );
  66. m_nSpkrVol = 0;
  67. m_nSpkrMode = 0;
  68. m_nState = STATE_NONE;
  69. m_nLastCommand = COMMAND_NONE;
  70. m_nRingCount = 0;
  71. m_nAnswerOnRing = 2;
  72. m_bReceiving = false;
  73. m_nWaitTimeout = 1000;
  74. m_bEnableReceive = true;
  75. InitHDLC();
  76. m_bHDLCMode = false;
  77. m_bGotOK = false;
  78. m_bECMSupported = true;
  79. m_nSendEncoding = FAXAPI_ENC_CCITT_T6;
  80. ZeroMemory( m_ParamMatrix, sizeof(m_ParamMatrix) );
  81. m_nSendBaud = FAXAPI_BAUD_14400;
  82. m_nRecvBaud = FAXAPI_BAUD_14400;
  83. m_nMaxSendBaud = FAXAPI_BAUD_33600;
  84. m_nMaxRecvBaud = FAXAPI_BAUD_33600;
  85. m_bPulseDialing = false;
  86. m_FaxThreadID = 0;
  87. m_nMaxPageRetries = 0; // no limit
  88. m_nMaxPageRetriesPageNo = -1;
  89. m_bTerminated = false;
  90. m_bLastPageGood = false;
  91. }
  92. CModem::~CModem()
  93. {
  94. }
  95. //////////////////////////////////////////////////////////////////////
  96. // Initialize - start the modem thread
  97. //////////////////////////////////////////////////////////////////////
  98. void CModem::Initialize( HANDLE hStop, DWORD faxThreadID )
  99. {
  100. m_FaxThreadID = faxThreadID;
  101. AddEvent( hStop );
  102. AddEvent( m_ReadOverlapped.hEvent );
  103. AddEvent( m_WriteOverlapped.hEvent );
  104. AddEvent( m_CommEventOverlapped.hEvent );
  105. StartThread();
  106. }
  107. //////////////////////////////////////////////////////////////////////
  108. // SetPort
  109. //////////////////////////////////////////////////////////////////////
  110. void CModem::SetPort( char* szPort )
  111. {
  112. m_sPort = szPort;
  113. }
  114. //////////////////////////////////////////////////////////////////////
  115. // Disconnect - send a message to initiate the disconnect
  116. //////////////////////////////////////////////////////////////////////
  117. void CModem::Disconnect(void)
  118. {
  119. PostMsg( WM_MODEM_DISCONNECT, 0, 0 );
  120. }
  121. //////////////////////////////////////////////////////////////////////
  122. // Disconnect - send a message to initiate the disconnect
  123. //////////////////////////////////////////////////////////////////////
  124. void CModem::RecvFax( char* szFaxFile )
  125. {
  126. InternalModemMsg* pMsg = new InternalModemMsg;
  127. strcpy( pMsg->szFile, szFaxFile );
  128. // m_FaxFile.SetFileName( szFaxFile );
  129. PostMsg( WM_MODEM_RECVFAX, (WPARAM)pMsg, 0 );
  130. }
  131. //////////////////////////////////////////////////////////////////////
  132. // SetInitString
  133. //////////////////////////////////////////////////////////////////////
  134. void CModem::SetInitString( LPCSTR szString )
  135. {
  136. m_sInitString.assign( szString );
  137. }
  138. //////////////////////////////////////////////////////////////////////
  139. // SetInitString
  140. //////////////////////////////////////////////////////////////////////
  141. void CModem::ChangeCSID( LPCSTR szString )
  142. {
  143. InternalModemMsg* pMsg = new InternalModemMsg;
  144. strcpy( pMsg->szNumber, szString );
  145. PostMsg( WM_MODEM_SETID, (WPARAM)pMsg, 0 );
  146. }
  147. //////////////////////////////////////////////////////////////////////
  148. // SetInitString
  149. //////////////////////////////////////////////////////////////////////
  150. void CModem::SetCSID( LPCSTR szString )
  151. {
  152. char szID[21];
  153. int nLen = 0;
  154. while( *szString && nLen < 20 )
  155. {
  156. if( *szString > 31 && *szString < 127 && *szString != 34 )
  157. {
  158. szID[nLen++] = toupper(*szString);
  159. }
  160. szString++;
  161. }
  162. szID[nLen] = 0;
  163. m_sLocalCSID.assign( szID );
  164. }
  165. //////////////////////////////////////////////////////////////////////
  166. // Connect - send a message to initiate the disconnect
  167. //////////////////////////////////////////////////////////////////////
  168. void CModem::SetSpkrParams( int nSpkrVol, int nSpkrMode )
  169. {
  170. m_nSpkrVol = nSpkrVol;
  171. m_nSpkrMode = nSpkrMode;
  172. }
  173. bool CModem::SendFax( char* szNumberToDial, char* szFaxFile )
  174. {
  175. InternalModemMsg* pMsg = new InternalModemMsg;
  176. strcpy( pMsg->szNumber, szNumberToDial );
  177. strcpy( pMsg->szFile, szFaxFile );
  178. // m_sNumberToDial.assign( szNumberToDial );
  179. // m_FaxFile.SetFileName( szFaxFile );
  180. PostMsg( WM_MODEM_SENDFAX, (WPARAM)pMsg, 0 );
  181. return true;
  182. }
  183. //////////////////////////////////////////////////////////////////////
  184. // OnStartup
  185. //////////////////////////////////////////////////////////////////////
  186. bool CModem::OnStartup( void )
  187. {
  188. m_sThreadName.assign( "Modem Thread" );
  189. if( CThread::OnStartup() )
  190. {
  191. InitWindow();
  192. PostMsg( WM_MODEM_CONNECT, 0, 0 );
  193. return true;
  194. }
  195. return false;
  196. }
  197. //////////////////////////////////////////////////////////////////////
  198. // OnShutdown - called before thread exits
  199. //////////////////////////////////////////////////////////////////////
  200. void CModem::OnShutdown( void )
  201. {
  202. CThread::OnShutdown();
  203. ShutdownWindow();
  204. if( m_bConnected )
  205. {
  206. DisconnectPort();
  207. m_nState = STATE_NONE;
  208. m_bConnected = false;
  209. }
  210. }
  211. //////////////////////////////////////////////////////////////////////
  212. // Handle message - return true if WM_QUIT received
  213. //////////////////////////////////////////////////////////////////////
  214. bool CModem::OnMsg( MSG* pMsg )
  215. {
  216. if( CThread::OnMsg( pMsg ) )
  217. return true;
  218. m_dwActivityTimer = GetTickCount();
  219. switch( pMsg->message )
  220. {
  221. case WM_MODEM_CONNECT:
  222. OnConnectMsg();
  223. break;
  224. case WM_MODEM_DISCONNECT:
  225. OnDisconnectMsg();
  226. break;
  227. case WM_MODEM_SENDFAX:
  228. OnSendFaxMsg( pMsg );
  229. break;
  230. case WM_MODEM_RECVFAX:
  231. OnRecvFaxMsg( pMsg );
  232. break;
  233. case WM_MODEM_ABORTFAX:
  234. OnAbortFaxMsg();
  235. break;
  236. case WM_MODEM_CLEARRINGCNT:
  237. m_nRingCount = 0;
  238. m_nState = STATE_IDLE;
  239. break;
  240. case WM_MODEM_SETID:
  241. {
  242. InternalModemMsg* pModemMsg = (InternalModemMsg*) pMsg->wParam;
  243. if( pModemMsg)
  244. {
  245. SetCSID( pModemMsg->szNumber );
  246. }
  247. delete pModemMsg;
  248. }
  249. break;
  250. }
  251. return false;
  252. }
  253. //////////////////////////////////////////////////////////////////////
  254. // Handle event - return true if cancel event set
  255. //////////////////////////////////////////////////////////////////////
  256. bool CModem::OnEvent( int nIndex )
  257. {
  258. switch( nIndex )
  259. {
  260. case 0:
  261. // Cancel event
  262. OnDisconnectMsg();
  263. return true;
  264. case 1:
  265. // Read event
  266. ReadEventSignalled();
  267. return false;
  268. case 2:
  269. // Write event
  270. WriteEventSignalled();
  271. return false;
  272. case 3:
  273. // WaitComm event
  274. WaitCommEventSignalled();
  275. return false;
  276. case 4:
  277. // Disconnect Event
  278. return true;
  279. }
  280. return false;
  281. }
  282. //////////////////////////////////////////////////////////////////////
  283. // OnConnectMsg
  284. //////////////////////////////////////////////////////////////////////
  285. void CModem::OnConnectMsg(void)
  286. {
  287. if( !m_bConnected )
  288. {
  289. m_nRingCount = 0;
  290. m_bConnected = ConnectPort( m_sLastError );
  291. if( !m_bConnected )
  292. {
  293. SignalEvent( EVENT_ERROR );
  294. m_nState = STATE_NONE;
  295. SignalEvent( EVENT_DISCONNECT );
  296. ExitAndDelete();
  297. }
  298. }
  299. }
  300. //////////////////////////////////////////////////////////////////////
  301. // OnDisconnectMsg
  302. //////////////////////////////////////////////////////////////////////
  303. void CModem::OnDisconnectMsg(void)
  304. {
  305. if( m_bConnected )
  306. {
  307. if( OnDisconnect() )
  308. {
  309. DisconnectPort();
  310. m_nState = STATE_NONE;
  311. SignalEvent( EVENT_DISCONNECT );
  312. m_bConnected = false;
  313. ExitAndDelete();
  314. }
  315. }
  316. }
  317. //////////////////////////////////////////////////////////////////////
  318. // OnSendFaxMsg
  319. //////////////////////////////////////////////////////////////////////
  320. void CModem::OnSendFaxMsg( MSG* pMsg )
  321. {
  322. InternalModemMsg* pModemMsg = (InternalModemMsg*) pMsg->wParam;
  323. if( pModemMsg == NULL)
  324. return;
  325. m_sNumberToDial.assign( pModemMsg->szNumber );
  326. m_FaxFile.SetFileName( pModemMsg->szFile );
  327. delete pModemMsg;
  328. m_nMaxPageRetriesPageNo = -1;
  329. }
  330. void CModem::OnRecvFaxMsg( MSG* pMsg )
  331. {
  332. InternalModemMsg* pModemMsg = (InternalModemMsg*) pMsg->wParam;
  333. if( pModemMsg == NULL)
  334. return;
  335. m_FaxFile.SetFileName( pModemMsg->szFile );
  336. delete pModemMsg;
  337. }
  338. void CModem::OnAbortFaxMsg(void)
  339. {
  340. }
  341. //////////////////////////////////////////////////////////////////////
  342. // SendCommand
  343. //////////////////////////////////////////////////////////////////////
  344. void CModem::SendCommand( int nCommand, char* szCmdString )
  345. {
  346. char szWorkBuffer[256];
  347. char* szCmd = NULL;
  348. if( szCmdString )
  349. {
  350. szCmd = szCmdString;
  351. }
  352. else if( nCommand == COMMAND_SETUP_STRING )
  353. {
  354. szCmd = (char*)m_sInitString.c_str();
  355. }
  356. else 
  357. {
  358. switch( nCommand )
  359. {
  360. case COMMAND_SET_SPKR_VOL:
  361. wsprintf( szWorkBuffer, s_CommonCmds[nCommand], m_nSpkrVol );
  362. szCmd = szWorkBuffer;
  363. break;
  364. case COMMAND_SET_SPKR_MODE:
  365. wsprintf( szWorkBuffer, s_CommonCmds[nCommand], m_nSpkrMode );
  366. szCmd = szWorkBuffer;
  367. break;
  368. case COMMAND_DIAL:
  369. if( m_bPulseDialing )
  370. {
  371. wsprintf( szWorkBuffer, "ATDP%s", m_sNumberToDial.c_str() );
  372. }
  373. else
  374. {
  375. wsprintf( szWorkBuffer, "ATDT%s", m_sNumberToDial.c_str() );
  376. }
  377. szCmd = szWorkBuffer;
  378. break;
  379. case COMMAND_SET_FLOW_CONTROL:
  380. wsprintf( szWorkBuffer, s_CommonCmds[nCommand], m_bCTSFlowControl ? 2 : 1 );
  381. szCmd = szWorkBuffer;
  382. break;
  383. default:
  384. if( nCommand >= 0 && nCommand < COMMAND_COUNT )
  385. {
  386. szCmd = s_CommonCmds[nCommand];
  387. }
  388. break;
  389. }
  390. }
  391. if( szCmd )
  392. {
  393. m_nLastCommand = nCommand;
  394. m_LastCommandString.assign( szCmd );
  395. m_bGotOK = false;
  396. KillTimer( TIMER_COMMAND );
  397. if( (nCommand != COMMAND_DIAL) && (nCommand != COMMAND_ANSWER) )
  398. {
  399. SetTimer( TIMER_COMMAND, 2000 );
  400. }
  401. // m_nLastCommandTickCount = GetTickCount();
  402. DoWrite( szCmd, strlen(szCmd), true );
  403. //wsprintf( szWorkBuffer, "Sent Command: %sn", m_LastCommandString.c_str() );
  404. //OutputDebugString( szWorkBuffer );
  405. }
  406. }
  407. //////////////////////////////////////////////////////////////////////
  408. // SignalEvent
  409. //////////////////////////////////////////////////////////////////////
  410. void CModem::SignalEvent( int nEvent, char info )
  411. {
  412. FaxApiModemMsg* pMsg = new FaxApiModemMsg;
  413. memset( pMsg, 0, sizeof(FaxApiModemMsg) );
  414. pMsg->m_cbSize = sizeof(FaxApiModemMsg);
  415. switch( nEvent )
  416. {
  417. case EVENT_ERROR:
  418. strncpy( pMsg->sz, m_sLastError.c_str(), FAXAPI_MODEMMSG_INFOLEN );
  419. pMsg->sz[FAXAPI_MODEMMSG_INFOLEN-1] = '';
  420. break;
  421. case EVENT_RECV_DIS:
  422. case EVENT_SENT_DIS:
  423. memcpy( &pMsg->p, &m_DISParams.p, sizeof(FaxApiParameters) );
  424. break;
  425. case EVENT_RECV_DCS:
  426. case EVENT_SENT_DCS:
  427. memcpy( &pMsg->p, &m_DCSParams.p, sizeof(FaxApiParameters) );
  428. break;
  429. case EVENT_GOT_REMOTEID:
  430. strcpy( pMsg->sz, m_sRemoteCSID.c_str() );
  431. trimws( pMsg->sz );
  432. break;
  433. case EVENT_START_PAGE:
  434. pMsg->t.nPages = GetPageCount();
  435. break;
  436. case EVENT_TERMINATE:
  437. strncpy( pMsg->sz, m_sLastError.c_str(), FAXAPI_MODEMMSG_INFOLEN );
  438. pMsg->sz[FAXAPI_MODEMMSG_INFOLEN-1] = '';
  439. pMsg->t.nPages = GetPageCount();
  440. pMsg->t.nSuccessful = (m_bSuccessful && GetPageCount() > 0 ) ? 1 : 0;
  441. break;
  442. case EVENT_CALLERID:
  443. strncpy( pMsg->sz, m_szLineBuff, FAXAPI_MODEMMSG_INFOLEN );
  444. pMsg->szID[FAXAPI_MODEMMSG_INFOLEN-1] = '';
  445. break;
  446. default:
  447. pMsg->sz[0] = info;
  448. break;
  449. }
  450. SendModemMessage( nEvent, pMsg );
  451. }
  452. void CModem::SignalEventString( int nEvent, LPCSTR szMsg )
  453. {
  454. FaxApiModemMsg* pMsg = new FaxApiModemMsg;
  455. memset( pMsg, 0, sizeof(FaxApiModemMsg) );
  456. pMsg->m_cbSize = sizeof(FaxApiModemMsg);
  457. strncpy( pMsg->sz, szMsg, FAXAPI_MODEMMSG_INFOLEN );
  458. pMsg->sz[FAXAPI_MODEMMSG_INFOLEN-1] = '';
  459. SendModemMessage( nEvent, pMsg );
  460. }
  461. void CModem::SendModemMessage( int nEvent, FaxApiModemMsg* pMsg )
  462. {
  463. strcpy( pMsg->szID, m_sPort.c_str() );
  464. PostThreadMessage( m_FaxThreadID, WM_MODEM_MESSAGE, (WPARAM)pMsg, nEvent );
  465. }
  466. //////////////////////////////////////////////////////////////////////
  467. // ErrorUnexpectedResponse
  468. //////////////////////////////////////////////////////////////////////
  469. void CModem::ErrorUnexpectedResponse( void )
  470. {
  471. char szMsg[512];
  472. wsprintf( szMsg, (char*)LoadString(GEN_RECEIVED_IN_RESPONSE_TO).c_str(), m_szLineBuff, m_LastCommandString.c_str() );
  473. m_sLastError.assign( szMsg );
  474. SignalEvent( EVENT_ERROR );
  475. }
  476. //////////////////////////////////////////////////////////////////////
  477. // ErrorConnectResponse
  478. //////////////////////////////////////////////////////////////////////
  479. void CModem::ErrorConnectResponse( void )
  480. {
  481. // For now, use the return string as the error description
  482. m_sLastError.assign( m_szLineBuff );
  483. SignalEvent( EVENT_ERROR );
  484. }
  485. void CModem::ProcSupportedSpeeds( LPSTR lpSpeeds, bool bSend )
  486. {
  487. LPSTR lpTok;
  488. int val;
  489. char szDefSpeeds[64];
  490. if( stricmp( m_szLineBuff, "ERROR" ) == 0 )
  491. {
  492. strcpy( szDefSpeeds, "3,24,48,72,73,74,96,97,98,121,122,145,146" );
  493. lpSpeeds = szDefSpeeds;
  494. }
  495. bool* bSupported = (bSend) ? &m_bSendSupported[0] : &m_bRecvSupported[0];
  496. ZeroMemory( bSupported, sizeof(bool) * MAX_CLS1SPEEDS );
  497. lpTok = strtok( lpSpeeds, ",");
  498. while( lpTok ) {
  499. val = atoi( lpTok );
  500. switch( val ) {
  501. case 24:
  502. bSupported[0] = 1;
  503. break;
  504. case 48:
  505. bSupported[1] = 1;
  506. break;
  507. case 72:
  508. bSupported[2] = 1;
  509. break;
  510. case 73:
  511. bSupported[6] = 1;
  512. break;
  513. case 96:
  514. bSupported[3] = 1;
  515. break;
  516. case 97:
  517. bSupported[7] = 1;
  518. break;
  519. case 121:
  520. bSupported[8] = 1;
  521. bSupported[4] = 1;
  522. break;
  523. case 145:
  524. bSupported[9] = 1;
  525. bSupported[5] = 1;
  526. break;
  527. }
  528. lpTok = strtok( NULL, "," );
  529. }
  530. if( bSend )
  531. {
  532. if( m_bSendSupported[9] )
  533. {
  534. m_nMaxSendBaud = 5;
  535. }
  536. else if( m_bSendSupported[8] )
  537. {
  538. m_nMaxSendBaud = 4;
  539. }
  540. else if( m_bSendSupported[7] )
  541. {
  542. m_nMaxSendBaud = 3;
  543. }
  544. else if( m_bSendSupported[6] )
  545. {
  546. m_nMaxSendBaud = 2;
  547. }
  548. else if( m_bSendSupported[1] )
  549. {
  550. m_nMaxSendBaud = 1;
  551. }
  552. else
  553. {
  554. m_nMaxSendBaud = 0;
  555. }
  556. if( m_nSendBaud > m_nMaxSendBaud )
  557. {
  558. m_nSendBaud = m_nMaxSendBaud;
  559. }
  560. }
  561. else
  562. {
  563. if( m_bRecvSupported[9] )
  564. {
  565. m_nMaxRecvBaud = 5;
  566. }
  567. else if( m_bRecvSupported[8] )
  568. {
  569. m_nMaxRecvBaud = 4;
  570. }
  571. else if( m_bRecvSupported[7] )
  572. {
  573. m_nMaxRecvBaud = 3;
  574. }
  575. else if( m_bRecvSupported[6] )
  576. {
  577. m_nMaxRecvBaud = 2;
  578. }
  579. else if( m_bRecvSupported[1] )
  580. {
  581. m_nMaxRecvBaud = 1;
  582. }
  583. else 
  584. {
  585. m_nMaxRecvBaud = 0;
  586. }
  587. if( m_nRecvBaud > m_nMaxRecvBaud )
  588. {
  589. m_nRecvBaud = m_nMaxRecvBaud;
  590. }
  591. }
  592. }
  593. bool CModem::GetCapParam( int nIndex, int nValue )
  594. {
  595. if( nIndex >= 0 && nIndex <= FAXAPI_MAXPARAMETERS && nValue >= 0 && nValue <= FAXAPI_MAXPARAMVALUE )
  596. {
  597. return m_ParamMatrix[nIndex][nValue];
  598. }
  599. return false;
  600. }
  601. int CModem::ProcCapValueIndex( LPSTR lpValue, int nIndex, bool bComma, bool bDash, int nLast )
  602. {
  603. int nCurrent = 0;
  604. char* p = lpValue;
  605. bool bHex = false;
  606. //OnFHNG
  607. while( *p )
  608. {
  609. if( IsHex(*p) )
  610. {
  611. bHex = true;
  612. break;
  613. }
  614. p++;
  615. }
  616. if( bHex )
  617. {
  618. sscanf( lpValue, "%X", &nCurrent );
  619. }
  620. else
  621. {
  622. nCurrent = atoi(lpValue);
  623. }
  624. if( bDash )
  625. {
  626. while( nLast <= nCurrent )
  627. {
  628. if( nIndex >= 0 && nIndex < FAXAPI_MAXPARAMETERS && nLast >= 0 && nLast < FAXAPI_MAXPARAMVALUE )
  629. {
  630. m_ParamMatrix[nIndex][nLast] = true;
  631. }
  632. nLast++;
  633. }
  634. }
  635. else 
  636. {
  637. if( nIndex >= 0 && nIndex < FAXAPI_MAXPARAMETERS && nCurrent >= 0 && nCurrent < FAXAPI_MAXPARAMVALUE )
  638. {
  639. m_ParamMatrix[nIndex][nCurrent] = true;
  640. }
  641. }
  642. return nCurrent;
  643. }
  644. void CModem::ProcCapValue( LPSTR lpValue, int nIndex )
  645. {
  646. char szN[32];
  647. bool bComma = false;
  648. bool bDash = false;
  649. int nLast = 0;
  650. int i = 0;
  651. char* p = lpValue;
  652. while( *p )
  653. {
  654. bool bProcessNumber = false;
  655. if( *p == ',' )
  656. {
  657. szN[i] = 0;
  658. nLast = ProcCapValueIndex( szN, nIndex, bComma, bDash, nLast );
  659. bComma = true;
  660. bDash = false;
  661. i = 0;
  662. }
  663. else if( *p == '-' )
  664. {
  665. szN[i] = 0;
  666. nLast = ProcCapValueIndex( szN, nIndex, bComma, bDash, nLast );
  667. bDash = true;
  668. bComma = false;
  669. i = 0;
  670. }
  671. else if( IsHexDigit( *p ) )
  672. {
  673. szN[i++] = *p;
  674. }
  675. p++;
  676. if( *p == ''  )
  677. {
  678. szN[i] = 0;
  679. nLast = ProcCapValueIndex( szN, nIndex, bComma, bDash, nLast );
  680. i = 0;
  681. }
  682. }
  683. }
  684. void CModem::ProcCapabilities( LPSTR lpCaps )
  685. {
  686. char szValue[32];
  687. bool bInParens = false;
  688. int i = 0;
  689. int j = 0;
  690. ZeroMemory( m_ParamMatrix, sizeof(m_ParamMatrix) );
  691. char* p = lpCaps;
  692. while( *p )
  693. {
  694. bool bProcessNumber = false;
  695. if( bInParens == false )
  696. {
  697. if( *p == '(' )
  698. {
  699. bInParens = true;
  700. }
  701. else if( *p == ',' )
  702. {
  703. bProcessNumber = true;
  704. }
  705. else 
  706. {
  707. if( i < (sizeof(szValue) - 1) )
  708. {
  709. szValue[i++] = *p;
  710. }
  711. }
  712. }
  713. else
  714. {
  715. if( *p == ')' )
  716. {
  717. bInParens = false;
  718. }
  719. else 
  720. {
  721. if( i < (sizeof(szValue) - 1) )
  722. {
  723. szValue[i++] = *p;
  724. }
  725. }
  726. }
  727. p++;
  728. if( *p == '' || bProcessNumber )
  729. {
  730. szValue[i] = 0;
  731. ProcCapValue( szValue, j );
  732. // next element
  733. i = 0;
  734. j++;
  735. }
  736. }
  737. }
  738. //////////////////////////////////////////////////////////////////////
  739. // Handle wait timeout - do periodic processing
  740. //////////////////////////////////////////////////////////////////////
  741. bool CModem::OnWaitTimeout( void )
  742. {
  743. DWORD nInActive = GetTickCount() - m_dwActivityTimer;
  744. CheckTimeouts( nInActive );
  745. return false;
  746. }
  747. void CModem::CheckTimeouts( DWORD dwInActive )
  748. {
  749. }
  750. void CModem::PurgeWriteQueue( void )
  751. {
  752. // Purge write queue
  753. deque<CWriteBuffer*>::iterator iter = m_WriteQueue.begin();
  754. while( iter != m_WriteQueue.end() )
  755. {
  756. delete (*iter);
  757. m_WriteQueue.pop_front();
  758. iter = m_WriteQueue.begin();
  759. }
  760. }
  761. void CModem::PurgeOutput( void )
  762. {
  763. PurgeWriteQueue();
  764. PurgeComm( m_hPort, PURGE_TXABORT | PURGE_TXCLEAR );
  765. }
  766. void CModem::DoHangup( void )
  767. {
  768. SendCommand( COMMAND_HANGUP );
  769. m_nState = STATE_DISCONNECT;
  770. }
  771. void CModem::PhaseHangup(void)
  772. {
  773. // if( strnicmp( m_szLineBuff, "OK", 2 ) == 0 )
  774. {
  775. m_bGotOK = true;
  776. KillTimer( TIMER_COMMAND );
  777. m_nState = STATE_IDLE;
  778. SignalEvent( EVENT_IDLE );
  779. }
  780. }
  781. void CModem::PhaseDisconnect(void)
  782. {
  783. // if( strnicmp( m_szLineBuff, "OK", 2 ) == 0 )
  784. {
  785. m_bGotOK = true;
  786. KillTimer( TIMER_COMMAND );
  787. DisconnectPort();
  788. m_nState = STATE_NONE;
  789. SignalEvent( EVENT_DISCONNECT );
  790. m_bConnected = false;
  791. ExitAndDelete();
  792. }
  793. }
  794. void CModem::Terminate()
  795. {
  796. if( m_bTerminated == false )
  797. {
  798. SignalEvent( EVENT_TERMINATE );
  799. PurgeWriteQueue();
  800. m_FaxFile.Close();
  801. KillTimer( TIMER_MAXPAGERETRIES );
  802. m_bTerminated = true;
  803. }
  804. }
  805. bool CModem::OkToAnswer( void )
  806. {
  807. return ( m_bEnableReceive && (m_nRingCount >= m_nAnswerOnRing) );
  808. }
  809. //////////////////////////////////////////////////////////////////////
  810. // OnRead
  811. //////////////////////////////////////////////////////////////////////
  812. void CModem::OnRead(void)
  813. {
  814. DWORD i;
  815. m_dwActivityTimer = GetTickCount();
  816. // char szMsg[80];
  817. // wsprintf( szMsg, "OnRead %d bytesn", m_BytesRead );
  818. // OutputDebugString( szMsg );
  819. for( i = 0; i < m_BytesRead; i++ )
  820. {
  821. //char szDigit[32];
  822. //wsprintf( szDigit, "%d:[%02x]n", i, m_szReadBuff[i] );
  823. //OutputDebugString( szDigit );
  824. if( m_bEolFlag )
  825. {
  826. if( (m_szReadBuff[i] != 'r') && (m_szReadBuff[i] != 'n') )
  827. {
  828. m_bEolFlag = false;
  829. }
  830. }
  831. if( !m_bEolFlag )
  832. {
  833. if( m_bHDLCMode ) // HDLC mode
  834. {
  835. if( m_bGotDLE ) 
  836. {
  837. m_bGotDLE = false;
  838. if( m_szReadBuff[i] == ETX )
  839. {
  840. OnHDLCFrame();
  841. InitLineParser();
  842. m_bHDLCMode = false;
  843. }
  844. else if( m_szReadBuff[i] == DLE )
  845. {
  846. if( m_nHDLCBuffPtr >= READBUF_SIZE )
  847. {
  848. OnPartialHDLCFrame();
  849. m_nHDLCBuffPtr = 0;
  850. }
  851. m_szHDLCBuff[m_nHDLCBuffPtr++] = m_szReadBuff[i];
  852. }
  853. else if( m_szReadBuff[i] == SUB )
  854. {
  855. if( m_nHDLCBuffPtr >= READBUF_SIZE )
  856. {
  857. OnPartialHDLCFrame();
  858. m_nHDLCBuffPtr = 0;
  859. }
  860. m_szHDLCBuff[m_nHDLCBuffPtr++] = DLE;
  861. if( m_nHDLCBuffPtr >= READBUF_SIZE )
  862. {
  863. OnPartialHDLCFrame();
  864. m_nHDLCBuffPtr = 0;
  865. }
  866. m_szHDLCBuff[m_nHDLCBuffPtr++] = DLE;
  867. }
  868. else
  869. {
  870. //OutputDebugString( "Illegal HDLC Coding!n" );
  871. }
  872. }
  873. else
  874. {
  875. if( m_szReadBuff[i] == DLE )
  876. {
  877. m_bGotDLE = true;
  878. }
  879. else
  880. {
  881. if( m_nHDLCBuffPtr >= READBUF_SIZE )
  882. {
  883. OnPartialHDLCFrame();
  884. InitHDLC();
  885. }
  886. m_szHDLCBuff[m_nHDLCBuffPtr++] = m_szReadBuff[i];
  887. }
  888. }
  889. // Sometimes NO CARRIER is returned w/o DLE-ETX
  890. if( (m_nHDLCBuffPtr > 9) && (m_nHDLCBuffPtr < 14) && strstr( (char*) m_szHDLCBuff, "NO CARRIER" ) )
  891. {
  892. m_bHDLCMode = false;
  893. memcpy( m_szLineBuff, m_szHDLCBuff, m_nHDLCBuffPtr );
  894. m_nLineBuffPtr = m_nHDLCBuffPtr;
  895. m_szLineBuff[m_nLineBuffPtr] = '';
  896. OnReadLine();
  897. InitLineParser();
  898. }
  899. }
  900. else // line mode
  901. {
  902. if( (m_szReadBuff[i] == 'r') || (m_szReadBuff[i] == 'n') )
  903. {
  904. m_bEolFlag = true;
  905. if( m_nLineBuffPtr > 0 )
  906. {
  907. m_szLineBuff[m_nLineBuffPtr] = '';
  908. //char szMsg[256];
  909. //wsprintf( szMsg, "OnRead:(%d:%d)n", m_BytesRead, i );
  910. //OutputDebugString( szMsg );
  911. // Ignore intermediate responses in init state
  912. if( ( m_nState > STATE_INIT ) || ((m_BytesRead - i) <= 2 ) )
  913. {
  914. OnReadLine();
  915. }
  916. else if( ( m_nState == STATE_INIT) && 
  917.      ((m_nLastCommand == COMMAND_QUERY_SEND_SPEEDS)||
  918.   (m_nLastCommand == COMMAND_QUERY_RECEIVE_SPEEDS)||
  919.   (m_nLastCommand >= COMMAND_QUERY_FCLASS)) )
  920. {
  921. OnReadLine();
  922. }
  923. if( !m_bHDLCMode )
  924. {
  925. InitLineParser();
  926. }
  927. }
  928. }
  929. else
  930. {
  931. if( m_nLineBuffPtr >= READBUF_SIZE )
  932. {
  933. //OutputDebugString( "Line buffer overflow!n" );
  934. InitLineParser();
  935. }
  936. m_szLineBuff[m_nLineBuffPtr++] = m_szReadBuff[i];
  937. }
  938. }
  939. }
  940. }
  941. }
  942. void CModem::OnHDLCFrame(void)
  943. {
  944. }
  945. void CModem::OnPartialHDLCFrame(void)
  946. {
  947. }
  948. void CModem::OnTimer( UINT nID )
  949. {
  950. //OutputDebugString( "CModem::OnTimern" );
  951. }
  952. //////////////////////////////////////////////////////////////////////
  953. // HandleMsg
  954. //////////////////////////////////////////////////////////////////////
  955. LRESULT CModem::HandleMsg( UINT message, WPARAM wParam, LPARAM lParam )
  956. {
  957. if( message == WM_TIMER )
  958. {
  959. OnTimer( wParam );
  960. }
  961. return DefWindowProc( m_hwnd, message, wParam, lParam );
  962. }
  963. int CModem::ParseFaxParams( int nMaxParams, int* pParams )
  964. {
  965. char szNumBuff[21];
  966. int j;
  967. int i;
  968. ZeroMemory( pParams, sizeof(int) * nMaxParams );
  969. char* p = m_szLineBuff + 5; // Skip +XXXX
  970. if ( *p == ':' ) // skip the colon
  971. {
  972. p++;
  973. }
  974. // advance to first digit
  975. while( *p && (IsHexDigit(*p) == false) && (*p != ',') )
  976. {
  977. p++;
  978. }
  979. for( i = 0; i < nMaxParams; i++ )
  980. {
  981. // check for end of string
  982. if( *p == '' )
  983. {
  984. return i;
  985. }
  986. j = 0;
  987. // advance to next comma
  988. while( *p && IsHexDigit(*p) && (j < 20) )
  989. {
  990. szNumBuff[j++] = *p++;
  991. }
  992. szNumBuff[j] = '';
  993. pParams[i] = atoi( szNumBuff );
  994. if( *p ) // advance past comma
  995. p++;
  996. }
  997. return i;
  998. }
  999. void CModem::ExitAndDelete(void)
  1000. {
  1001. OnShutdown();
  1002. delete this;
  1003. ExitThread(0);
  1004. }
  1005. bool CModem::IsRing(void)
  1006. {
  1007. if( stricmp( m_szLineBuff, "RING" ) == 0 )
  1008. {
  1009. return true;
  1010. }
  1011. if( !m_sRingCodes.empty() )
  1012. {
  1013. if( strchr( m_sRingCodes.c_str(), '1' ) )
  1014. {
  1015. if( ( stricmp( m_szLineBuff, "RING1" ) == 0 ) || ( stricmp( m_szLineBuff, "RINGA" ) == 0 ) )
  1016. {
  1017. return true;
  1018. }
  1019. }
  1020. if( strchr( m_sRingCodes.c_str(), '2' ) )
  1021. {
  1022. if( ( stricmp( m_szLineBuff, "RING2" ) == 0 ) || ( stricmp( m_szLineBuff, "RINGB" ) == 0 ) )
  1023. {
  1024. return true;
  1025. }
  1026. }
  1027. if( strchr( m_sRingCodes.c_str(), '3' ) )
  1028. {
  1029. if( ( stricmp( m_szLineBuff, "RING3" ) == 0 ) || ( stricmp( m_szLineBuff, "RINGC" ) == 0 ) )
  1030. {
  1031. return true;
  1032. }
  1033. }
  1034. }
  1035. return false;
  1036. }
  1037. void CModem::AbortFax(void)
  1038. {
  1039. PostMsg( WM_MODEM_ABORTFAX, 0, 0 );
  1040. }
  1041. bool CModem::IsHexDigit( char digit )
  1042. {
  1043. return (strchr( "1234567890ABCDEFabcdef", digit ) != NULL);
  1044. }
  1045. bool CModem::IsHex( char digit )
  1046. {
  1047. return (strchr( "ABCDEFabcdef", digit ) != NULL);
  1048. }
  1049. void CModem::Abort( bool bUserCancelled )
  1050. {
  1051. }
  1052. void CModem::ClearRingCount(void) 
  1053. PostMsg( WM_MODEM_CLEARRINGCNT, 0, 0 );
  1054. };
  1055. void CModem::SetMaxPageRetriesTimer(void)
  1056. {
  1057. DWORD dwTimeout = 0;
  1058. if( m_nMaxPageRetries < 1 )
  1059. return;
  1060. int nPageNo = GetPageCount();
  1061. if( nPageNo > m_nMaxPageRetriesPageNo )
  1062. {
  1063. KillTimer( TIMER_MAXPAGERETRIES );
  1064. m_nMaxPageRetriesPageNo = nPageNo;
  1065. // have to be careful how this timeout is computed so we don't overflow
  1066. unsigned int nSecsPerPage = m_FaxFile.GetTotalPageSize() / (Cls2FaxParamBitRates[m_DCSParams.p.BitRate] / 8) ;
  1067. dwTimeout = m_nMaxPageRetries * 1000 * (15 + nSecsPerPage);
  1068. SetTimer( TIMER_MAXPAGERETRIES, dwTimeout );
  1069. //char szMsg[128];
  1070. //wsprintf( szMsg, "Setting timeout %d for page %d (%d bytes) Bitrate=%dn", dwTimeout, nPageNo, m_FaxFile.GetTotalPageSize(), Cls2FaxParamBitRates[m_DCSParams.p.BitRate] );
  1071. //OutputDebugString( szMsg );
  1072. }
  1073. }