/*++ Copyright (c) 1996 Microsoft Corporation Module Name: t30api.c Abstract: This is the interface with T.30 DLL Author: Rafael Lisitsa (RafaelL) 2-Feb-1996 Revision History: --*/ #define DEFINE_T30_GLOBALS #include "prep.h" #include "tiff.h" #include "glbproto.h" #include "t30gl.h" ///RSL Wes should export this. #define TAPI_VERSION 0x00020000 #define ABORT_ACK_TIMEOUT 20000 /////////////////////////////////////////////////////////////////////////////////// VOID CALLBACK T30LineCallBackFunctionA( HANDLE hFax, DWORD hDevice, DWORD dwMessage, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2, DWORD_PTR dwParam3 ) { LONG_PTR i; PThrdGlbl pTG = NULL; char rgchTemp128[128]; LPSTR lpszMsg = "Unknown"; MyDebugPrint(pTG, LOG_ALL, "!!! LineCallBack !!! hFax=%lx, dev=%lx, msg=%lx, dwInst=%lx,P1=%lx, P2=%lx, P3=%lx\n", hFax, hDevice, dwMessage, dwInstance, dwParam1, dwParam2, (unsigned long) dwParam3); // find the thread that this callback belongs to //---------------------------------------------- i = (LONG_PTR) hFax; if (i < 1 || i >= MAX_T30_CONNECT) { MyDebugPrint(pTG, LOG_ALL, "T30LineCallback-wrong handle=%x\n", i); return; } if ( (! T30Inst[i].fAvail) && T30Inst[i].pT30) { pTG = (PThrdGlbl) T30Inst[i].pT30; } else { MyDebugPrint(pTG, LOG_ERR, "ERROR:T30LineCallback-handle=%x invalid \n", i); return; } switch (dwMessage) { case LINE_LINEDEVSTATE: lpszMsg = "LINE_LINEDEVSTATE"; if (dwParam1 == LINEDEVSTATE_RINGING) { MyDebugPrint(pTG, LOG_ALL, "Ring Count = %lx\n", (unsigned long) dwParam3); } else if (dwParam1 == LINEDEVSTATE_REINIT) { } break; case LINE_ADDRESSSTATE: lpszMsg = "LINE_ADDRESSSTATE"; break; /* process state transition */ case LINE_CALLSTATE: lpszMsg = "LINE_CALLSTATE"; if (dwParam1 == LINECALLSTATE_CONNECTED) { pTG->fGotConnect = TRUE; } else if (dwParam1 == LINECALLSTATE_IDLE) { if (pTG->fDeallocateCall == 0) { pTG->fDeallocateCall = 1; #if 0 // // this is now performed in the fax service // lRet = lineDeallocateCall( (HCALL) hDevice); if (lRet) { MyDebugPrint(pTG, LOG_ERR, "ERROR: IDLE lineDeallocateCall returns %lx\n", lRet); } else { MyDebugPrint(pTG, LOG_ALL, "IDLE lineDeallocateCall SUCCESS\n"); } #endif } } break; case LINE_CREATE: lpszMsg = "LINE_CREATE"; break; case LINE_CLOSE: lpszMsg = "LINE_CLOSE"; break; // LINE_CLOSE /* handle simple tapi request. */ case LINE_REQUEST: lpszMsg = "LINE_REQUEST"; break; // LINE_REQUEST /* handle the assync completion of TAPI functions lineMakeCall/lineDropCall */ case LINE_REPLY: lpszMsg = "LINE_REPLY"; if (!hDevice) {itapi_async_signal(pTG, (DWORD)dwParam1, (DWORD)dwParam2, dwParam3);} else MyDebugPrint(pTG, LOG_ALL, "Ignoring LINE_REPLY with nonzero device\n"); break; /* other messages that can be processed */ case LINE_CALLINFO: lpszMsg = "LINE_CALLINFO"; break; case LINE_DEVSPECIFIC: lpszMsg = "LINE_DEVSPECIFIC"; break; case LINE_DEVSPECIFICFEATURE: lpszMsg = "LINE_DEVSPECIFICFEATURE"; break; case LINE_GATHERDIGITS: lpszMsg = "LINE_GATHERDIGITS"; break; case LINE_GENERATE: lpszMsg = "LINE_GENERATE"; break; case LINE_MONITORDIGITS: lpszMsg = "LINE_MONITORDIGITS"; break; case LINE_MONITORMEDIA: lpszMsg = "LINE_MONITORMEDIA"; break; case LINE_MONITORTONE: lpszMsg = "LINE_MONITORTONE"; break; } /* switch */ _stprintf(rgchTemp128, "%s(p1=0x%lx, p2=0x%lx, p3=0x%lx)", (LPTSTR) lpszMsg, (unsigned long) dwParam1, (unsigned long) dwParam2, (unsigned long) dwParam3); MyDebugPrint(pTG, LOG_ALL, "Device:0x%lx; Message:%s\n", (unsigned long) hDevice, (LPTSTR) rgchTemp128); } /* LineCallBackProc */ /////////////////////////////////////////////////////////////////////////////////// BOOL WINAPI FaxDevInitializeA( IN HLINEAPP LineAppHandle, IN HANDLE HeapHandle, OUT PFAX_LINECALLBACK *LineCallbackFunction, IN PFAX_SERVICE_CALLBACK FaxServiceCallback ) /*++ Routine Description: Device Provider Initialization. Arguments: Return Value: --*/ { int i; LONG lRet; TCHAR LogFileLocation[256]; HKEY hKey; DWORD dwType; DWORD dwSizeNeed; int iLen; gT30.LineAppHandle = LineAppHandle; gT30.HeapHandle = HeapHandle; gT30.fInit = TRUE; HeapExistingInitialize(gT30.HeapHandle); FaxTiffInitialize(); *LineCallbackFunction = T30LineCallBackFunction; for (i=1; i _MAX_FNAME - 15) { MyDebugPrint( (PThrdGlbl) 0, LOG_ERR, "FaxDevInit__A GetTempPathA needs %d have %d bytes\n", gT30.dwLengthTmpDirectory , (_MAX_FNAME - 15) ); return (FALSE); } if (!gT30.dwLengthTmpDirectory) { MyDebugPrint( (PThrdGlbl) 0, LOG_ERR, "FaxDevInit__A GetTempPathA fails le=%x\n", GetLastError() ); return (FALSE); } MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: FaxDevInit__A hLineApp=%x heap=%x TempDir=%s Len=%d at %ld \n", LineAppHandle, HeapHandle, gT30.TmpDirectory, gT30.dwLengthTmpDirectory, GetTickCount() ); gT30.Status = STATUS_OK; return (TRUE); } /////////////////////////////////////////////////////////////////////////////////// BOOL WINAPI FaxDevStartJobA( HLINE LineHandle, DWORD DeviceId, PHANDLE pFaxHandle, HANDLE CompletionPortHandle, ULONG_PTR CompletionKey ) /*++ Routine Description: Device Provider Initialization. Arguments: Return Value: --*/ { PThrdGlbl pTG=NULL; int i; int fFound=0; MyDebugPrint(pTG, LOG_ALL, "EP: FaxDevStartJob__A LineHandle=%x, DevID=%x, pFaxH=%x Port=%x, Key=%x at %ld \n", LineHandle, DeviceId, pFaxHandle, CompletionPortHandle, CompletionKey, GetTickCount() ); gT30.CntConnect++; if (gT30.CntConnect >= MAX_T30_CONNECT) { MyDebugPrint(pTG, LOG_ERR, "ERROR: Exceeded # of connections (curr=%d, allowed=%d\n", gT30.CntConnect, MAX_T30_CONNECT ); return (FALSE); } if ( (pTG = (PThrdGlbl) T30AllocThreadGlobalData() ) == NULL ) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevStartJob: can't malloc\n"); return (FALSE); } EnterCriticalSection(&T30CritSection); for (i=1; iLineHandle = LineHandle; pTG->DeviceId = DeviceId; pTG->FaxHandle = (HANDLE) pTG; pTG->CompletionPortHandle = CompletionPortHandle; pTG->CompletionKey = CompletionKey; // initialization //--------------------------- pTG->hevAsync = CreateEvent(NULL, FALSE, FALSE, NULL); pTG->CtrlEvent = CreateEvent(NULL, FALSE, FALSE, NULL); pTG->ThrdSignal = CreateEvent(NULL, FALSE, FALSE, NULL); pTG->ThrdDoneSignal = CreateEvent(NULL, FALSE, FALSE, NULL); pTG->ThrdAckTerminateSignal = CreateEvent(NULL, FALSE, FALSE, NULL); pTG->FirstPageReadyTxSignal = CreateEvent(NULL, FALSE, FALSE, NULL); pTG->AbortReqEvent = CreateEvent(NULL, TRUE, FALSE, NULL); pTG->AbortAckEvent = CreateEvent(NULL, FALSE, FALSE, NULL); ResetEvent(pTG->AbortReqEvent); pTG->fWaitingForEvent = FALSE; pTG->fDeallocateCall = 0; MyAllocInit(pTG); pTG->StatusId = 0; pTG->StringId = 0; pTG->PageCount = 0; pTG->CSI = 0; pTG->CallerId = 0; pTG->RoutingInfo = 0; // helper image threads sync. flags pTG->AckTerminate = 1; pTG->fOkToResetAbortReqEvent = 1; pTG->Inst.awfi.fLastPage = 0; return (TRUE); } /////////////////////////////////////////////////////////////////////////////////// BOOL WINAPI FaxDevEndJobA( HANDLE FaxHandle ) /*++ Routine Description: Device Provider Initialization. Arguments: Return Value: --*/ { PThrdGlbl pTG=NULL; LONG_PTR i; MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: FaxDevEndJob FaxHandle=%x \n", FaxHandle); // find instance data //------------------------ i = (LONG_PTR) FaxHandle; if (i < 1 || i >= MAX_T30_CONNECT) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevEndJob - got wrong FaxHandle=%d\n", i); return (FALSE); } if (T30Inst[i].fAvail) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevEndJob - got wrong FaxHandle (marked as free) %d\n", i); return (FALSE); } pTG = (PThrdGlbl) T30Inst[i].pT30; if (pTG->hevAsync) { CloseHandle(pTG->hevAsync); } if (pTG->CtrlEvent) { CloseHandle(pTG->CtrlEvent); } if (pTG->StatusId == FS_NOT_FAX_CALL) { CloseHandle( (HANDLE) pTG->Comm.nCid ); } if (pTG->ThrdSignal) { CloseHandle(pTG->ThrdSignal); } if (pTG->ThrdDoneSignal) { CloseHandle(pTG->ThrdDoneSignal); } if (pTG->ThrdAckTerminateSignal) { CloseHandle(pTG->ThrdAckTerminateSignal); } if (pTG->FirstPageReadyTxSignal) { CloseHandle(pTG->FirstPageReadyTxSignal); } if (pTG->AbortReqEvent) { CloseHandle(pTG->AbortReqEvent); } if (pTG->AbortAckEvent) { CloseHandle(pTG->AbortAckEvent); } if (pTG->hThread) { CloseHandle(pTG->hThread); } MemFree(pTG->lpwFileName); pTG->fRemoteIdAvail = 0; if (pTG->RemoteID) { MemFree(pTG->RemoteID); } CleanModemInfStrings(pTG); MemFree(pTG); EnterCriticalSection(&T30CritSection); T30Inst[i].fAvail = TRUE; T30Inst[i].pT30 = NULL; gT30.CntConnect--; LeaveCriticalSection(&T30CritSection); MyDebugPrint(0, LOG_ALL, "FaxDevEndJob %d \n", FaxHandle); // RSL PrintAllocationsT30(); return (TRUE); } /////////////////////////////////////////////////////////////////////////////////// BOOL WINAPI FaxDevSendA( IN HANDLE FaxHandle, IN PFAX_SEND_A FaxSend, IN PFAX_SEND_CALLBACK FaxSendCallback ) /*++ Routine Description: Arguments: Return Value: --*/ { LONG_PTR i; PThrdGlbl pTG=NULL; LONG lRet; DWORD dw; LPVARSTRING lpVarStr=0; LPDEVICEID lpDeviceID=0; LPLINEDEVCAPS lpLineDevCaps; LPSTR lpszFaxNumber; BYTE buf[ sizeof(LINEDEVCAPS)+1000 ]; LONG lResult=0; LPLINECALLPARAMS lpCallParams; HCALL CallHandle; BYTE rgby [sizeof(LINETRANSLATEOUTPUT)+64]; LPLINETRANSLATEOUTPUT lplto1 = (LPLINETRANSLATEOUTPUT) rgby; LPLINETRANSLATEOUTPUT lplto; BOOL RetCode; DWORD dwNeededSize; LPDEVCFG lpDevCfg; LPMODEMSETTINGS lpModemSettings; LPMDM_DEVSPEC lpDSpec; int fFound=0; int RecoveryIndex = -1; char rgchKey[256]; HKEY hKey; DWORD dwType; DWORD dwSize; __try { MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: FaxDevSendA FaxHandle=%x, FaxSend=%x, FaxSendCallback=%x at %ld \n", FaxHandle, FaxSend, FaxSendCallback, GetTickCount() ); // find instance data //------------------------ i = (LONG_PTR) FaxHandle; if (i < 1 || i >= MAX_T30_CONNECT) { MemFree(FaxSend->FileName); MemFree(FaxSend->CallerName); MemFree(FaxSend->CallerNumber); MemFree(FaxSend->ReceiverName); MemFree(FaxSend->ReceiverNumber); return (FALSE); } if (T30Inst[i].fAvail) { MemFree(FaxSend->FileName); MemFree(FaxSend->CallerName); MemFree(FaxSend->CallerNumber); MemFree(FaxSend->ReceiverName); MemFree(FaxSend->ReceiverNumber); return (FALSE); } pTG = (PThrdGlbl) T30Inst[i].pT30; pTG->RecoveryIndex = -1; lpszFaxNumber = FaxSend->ReceiverNumber; pTG->Operation = T30_TX; // store LocalID if (FaxSend->CallerNumber == NULL) { pTG->LocalID[0] = 0; } else { _fmemcpy(pTG->LocalID, FaxSend->CallerNumber, min (_fstrlen(FaxSend->CallerNumber), sizeof(pTG->LocalID) - 1) ); pTG->LocalID [ min (_fstrlen(FaxSend->CallerNumber), sizeof(pTG->LocalID) - 1) ] = 0; } // go to TAPI pass-through mode //------------------------------- lpCallParams = itapi_create_linecallparams(); if (!itapi_async_setup(pTG)) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevSend: itapi_async_setup failed \n"); MemFree (lpCallParams); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } lRet = lineMakeCall (pTG->LineHandle, &CallHandle, lpszFaxNumber, 0, lpCallParams); if (lRet < 0) { MyDebugPrint(pTG, LOG_ERR, "ERROR: lineMakeCall returns ERROR value 0x%lx\n", (unsigned long) lRet); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_LINE_UNAVAILABLE); MemFree (lpCallParams); RetCode = FALSE; goto l_exit; } else { MyDebugPrint(pTG, LOG_ALL, "lineMakeCall returns 0x%lx\n", (unsigned long) lRet); } if(!itapi_async_wait(pTG, (DWORD)lRet, (LPDWORD)&lRet, NULL, ASYNC_TIMEOUT)) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevSend: itapi_async_wait failed \n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_LINE_UNAVAILABLE); MemFree (lpCallParams); RetCode = FALSE; goto l_exit; } // now we wait for the connected message //-------------------------------------- for (dw=50; dw<10000; dw = dw*120/100) { Sleep(dw); if (pTG->fGotConnect) break; } if (!pTG->fGotConnect) { MyDebugPrint(pTG, LOG_ERR, "ERROR: Failure waiting for CONNECTED message....\n"); // We ignore... goto failure1; } MemFree (lpCallParams); pTG->CallHandle = CallHandle; // // Add entry to the Recovery Area. // fFound = 0; for (i=0; iLineHandle; T30Recovery[i].CallHandle = CallHandle; T30Recovery[i].DeviceId = pTG->DeviceId; T30Recovery[i].CompletionPortHandle = pTG->CompletionPortHandle; T30Recovery[i].CompletionKey = pTG->CompletionKey; T30Recovery[i].TiffThreadId = 0; T30Recovery[i].TimeStart = GetTickCount(); T30Recovery[i].TimeUpdated = T30Recovery[i].TimeStart; T30Recovery[i].CkSum = ComputeCheckSum( (LPDWORD) &T30Recovery[i].fAvail, sizeof ( T30_RECOVERY_GLOB ) / sizeof (DWORD) - 1); LeaveCriticalSection(&T30RecoveryCritSection); fFound = 1; RecoveryIndex = (int)i; pTG->RecoveryIndex = (int)i; break; } } if (! fFound) { MyDebugPrint(pTG, LOG_ERR, "ERROR:Couldn't find available space for Recovery\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } // get the handle to a Comm port //---------------------------------- lpVarStr = (LPVARSTRING) MemAlloc(IDVARSTRINGSIZE); if (!lpVarStr) { MyDebugPrint(pTG, LOG_ERR, "ERROR:Couldn't allocate space for lpVarStr\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } _fmemset(lpVarStr, 0, IDVARSTRINGSIZE); lpVarStr->dwTotalSize = IDVARSTRINGSIZE; lRet = lineGetID(pTG->LineHandle, 0, // +++ addr CallHandle, LINECALLSELECT_CALL, // dwSelect, lpVarStr, //lpDeviceID, "comm/datamodem" ); //lpszDeviceClass if (lRet) { MyDebugPrint(pTG, LOG_ERR, "ERROR:lineGetID returns error 0x%lx\n", (unsigned long) lRet); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_LINE_UNAVAILABLE); RetCode = FALSE; goto l_exit; } // extract id if (lpVarStr->dwStringFormat != STRINGFORMAT_BINARY) { MyDebugPrint(pTG, LOG_ERR, "ERROR: String format is not binary\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } if (lpVarStr->dwUsedSizefFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } lpDeviceID = (LPDEVICEID) ((LPBYTE)(lpVarStr)+lpVarStr->dwStringOffset); MyDebugPrint(pTG, LOG_ALL, "lineGetID returns handle 0x%08lx, \"%s\"\n", (ULONG_PTR) lpDeviceID->hComm, (LPSTR) lpDeviceID->szDeviceName); pTG->hComm = lpDeviceID->hComm; if (BAD_HANDLE(pTG->hComm)) { MyDebugPrint(pTG, LOG_ERR, "ERR:lineGetID returns NULL hComm\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } // get the Modem configuration (speaker, etc.) from TAPI //------------------------------------------------------ _fmemset(lpVarStr, 0, IDVARSTRINGSIZE); lpVarStr->dwTotalSize = IDVARSTRINGSIZE; lResult = lineGetDevConfig(pTG->DeviceId, lpVarStr, "comm/datamodem"); if (lResult) { if (lpVarStr->dwTotalSize < lpVarStr->dwNeededSize) { dwNeededSize = lpVarStr->dwNeededSize; MemFree (lpVarStr); if ( ! (lpVarStr = (LPVARSTRING) MemAlloc(dwNeededSize) ) ) { MyDebugPrint(pTG, LOG_ERR, "ERR: Can't allocate %d bytes for lineGetDevConfig\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } _fmemset(lpVarStr, 0, dwNeededSize); lpVarStr->dwTotalSize = dwNeededSize; lResult = lineGetDevConfig(pTG->DeviceId, lpVarStr, "comm/datamodem"); if (lResult) { MyDebugPrint(pTG, LOG_ERR, "ERR: lineGetDevConfig returns %x, le=%x", lResult, GetLastError() ); MemFree (lpVarStr); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } } else { MyDebugPrint(pTG, LOG_ERR, "ERR: 1st lineGetDevConfig returns %x, le=%x", lResult, GetLastError() ); MemFree (lpVarStr); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } } // // extract DEVCFG // if (lpVarStr->dwStringFormat != STRINGFORMAT_BINARY) { MyDebugPrint(pTG, LOG_ERR, "ERROR: String format is not binary for lineGetDevConfig\n"); MemFree (lpVarStr); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } if (lpVarStr->dwUsedSizefFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } lpDevCfg = (LPDEVCFG) ((LPBYTE)(lpVarStr)+lpVarStr->dwStringOffset); lpModemSettings = (LPMODEMSETTINGS) ( (LPBYTE) &(lpDevCfg->commconfig.wcProviderData) ); pTG->dwSpeakerVolume = lpModemSettings->dwSpeakerVolume; pTG->dwSpeakerMode = lpModemSettings->dwSpeakerMode; if ( lpModemSettings->dwPreferredModemOptions & MDM_BLIND_DIAL ) { pTG->fBlindDial = 1; } else { pTG->fBlindDial = 0; } MyDebugPrint(pTG, LOG_ALL, "lineGetDevConfig returns SpeakerVolume=%x, Mode=%x BlindDial=%d \n", pTG->dwSpeakerVolume, pTG->dwSpeakerMode, pTG->fBlindDial ); MemFree (lpVarStr); lpVarStr=0; // get dwPermanentLineID // --------------------------- lpLineDevCaps = (LPLINEDEVCAPS) buf; _fmemset(lpLineDevCaps, 0, sizeof (buf) ); lpLineDevCaps->dwTotalSize = sizeof(buf); lResult = lineGetDevCaps(gT30.LineAppHandle, pTG->DeviceId, TAPI_VERSION, 0, lpLineDevCaps); if (lResult) { MyDebugPrint(pTG, LOG_ERR, "ERROR:lineGetDevCaps failed\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } if (lpLineDevCaps->dwNeededSize > lpLineDevCaps->dwTotalSize) { MyDebugPrint(pTG, LOG_ERR, "ERROR:lineGetDevCaps NOT enough MEMORY\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } // Save the permanent ID. //------------------------ pTG->dwPermanentLineID = lpLineDevCaps->dwPermanentLineID; _stprintf (pTG->lpszPermanentLineID, "%08d\\Modem", pTG->dwPermanentLineID); MyDebugPrint(pTG, LOG_ALL, "Permanent Line ID=%s\n", pTG->lpszPermanentLineID); // Get the Unimodem key name for this device //------------------------------------------ lpDSpec = (LPMDM_DEVSPEC) ( ( (LPBYTE) lpLineDevCaps) + lpLineDevCaps->dwDevSpecificOffset); if ( (lpLineDevCaps->dwDevSpecificSize < sizeof(MDM_DEVSPEC) ) || (lpLineDevCaps->dwDevSpecificSize <= lpDSpec->dwKeyOffset) ) { MyDebugPrint(pTG, LOG_ERR, "Devspecifc caps size is only %lu", (unsigned long) lpLineDevCaps->dwDevSpecificSize ); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } else { UINT u = lpLineDevCaps->dwDevSpecificSize - lpDSpec->dwKeyOffset; #define szAPPEND "\\FAX" if ( (lpDSpec->dwContents != 1) || (lpDSpec->dwKeyOffset != 8 ) ) { MyDebugPrint(pTG, LOG_ERR, "Nonstandard Devspecific: dwContents=%lu; dwKeyOffset=%lu", (unsigned long) lpDSpec->dwContents, (unsigned long) lpDSpec->dwKeyOffset ); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } if (u) { _fmemcpy(rgchKey, lpDSpec->rgby, u); if (rgchKey[u]) { MyDebugPrint(pTG, LOG_ERR, "rgchKey not null terminated!" ); rgchKey[u-1]=0; } // // Get ResponsesKeyName // lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, rgchKey, 0, KEY_READ, &hKey); if (lRet != ERROR_SUCCESS) { MyDebugPrint(pTG, LOG_ERR, "Can't read Unimodem key %s\n", rgchKey); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } dwSize = sizeof( pTG->ResponsesKeyName); lRet = RegQueryValueEx( hKey, "ResponsesKeyName", 0, &dwType, pTG->ResponsesKeyName, &dwSize); RegCloseKey(hKey); if (lRet != ERROR_SUCCESS) { MyDebugPrint(pTG, LOG_ERR, "Can't read Unimodem key\\ResponsesKeyName %s\n", rgchKey); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } lstrcpy(pTG->lpszUnimodemKey, rgchKey); // Append "\\Fax" to the key u = lstrlen(rgchKey); if (u) { lstrcpy(rgchKey+u, (LPSTR) szAPPEND); } lstrcpy(pTG->lpszUnimodemFaxKey, rgchKey); MyDebugPrint(pTG, LOG_ALL, "Unimodem Fax key=%s\n", pTG->lpszUnimodemFaxKey); } } // Convert the destination# to a dialable //-------------------------------------------- // find out how big a buffer should be // _fmemset(rgby, 0, sizeof(rgby)); lplto1->dwTotalSize = sizeof(rgby); lRet = lineTranslateAddress (gT30.LineAppHandle, pTG->DeviceId, TAPI_VERSION, lpszFaxNumber, 0, // dwCard LINETRANSLATEOPTION_CANCELCALLWAITING, lplto1); if (lRet) { MyDebugPrint(pTG, LOG_ERR, "ERROR:Can't translate dest. address %s\n", lpszFaxNumber); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } if (lplto1->dwNeededSize <= 0) { MyDebugPrint(pTG, LOG_ERR, "ERROR:Can't dwNeededSize<0 for Fax# %s\n", lpszFaxNumber); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } lplto = MemAlloc(lplto1->dwNeededSize); if (! lplto) { MyDebugPrint(pTG, LOG_ERR, "ERROR:Couldn't allocate space for lplto\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } lplto->dwTotalSize = lplto1->dwNeededSize; lRet = lineTranslateAddress (gT30.LineAppHandle, pTG->DeviceId, TAPI_VERSION, lpszFaxNumber, 0, // dwCard LINETRANSLATEOPTION_CANCELCALLWAITING, lplto); if (lRet) { MyDebugPrint(pTG, LOG_ERR, "ERROR:Can't translate dest. address %s\n", lpszFaxNumber); MemFree(lplto); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } if (lplto->dwNeededSize > lplto->dwTotalSize) { MyDebugPrint(pTG, LOG_ERR, "ERROR: NeedSize=%d > TotalSize=%d for Fax# %s\n", lplto->dwNeededSize ,lplto->dwTotalSize, lpszFaxNumber); MemFree(lplto); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } _fmemcpy (pTG->lpszDialDestFax, ( (char *) lplto) + lplto->dwDialableStringOffset, lplto->dwDialableStringSize); MyDebugPrint(pTG, LOG_ALL, "Dialable Dest is %s\n", pTG->lpszDialDestFax); MemFree(lplto); /// RSL -revisit, may decrease prty during computation if (! SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) ) { MyDebugPrint(pTG, LOG_ERR, "ERROR: SetThreadPriority TIME CRITICAL failed le=%x", GetLastError() ); } // initialize modem //-------------------- T30ModemInit(pTG, pTG->hComm, 0, LINEID_TAPI_PERMANENT_DEVICEID, DEF_BASEKEY, pTG->lpszPermanentLineID, fMDMINIT_ANSWER); pTG->Inst.ProtParams.uMinScan = MINSCAN_0_0_0; ET30ProtSetProtParams(pTG, &pTG->Inst.ProtParams, pTG->FComModem.CurrMdmCaps.uSendSpeeds, pTG->FComModem.CurrMdmCaps.uRecvSpeeds); InitCapsBC( pTG, (LPBC) &pTG->Inst.SendCaps, sizeof(pTG->Inst.SendCaps), SEND_CAPS); // store the TIFF filename //------------------------- pTG->lpwFileName = AnsiStringToUnicodeString(FaxSend->FileName); if ( !pTG->fTiffOpenOrCreated) { pTG->Inst.hfile = PtrToUlong (TiffOpenW (pTG->lpwFileName, &pTG->TiffInfo, TRUE) ); if (! (pTG->Inst.hfile)) { MyDebugPrint(pTG, LOG_ERR, "ERROR:Can't open tiff file %s\n", pTG->lpwFileName); // pTG->StatusId = FS_TIFF_SRC_BAD pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } if (pTG->TiffInfo.YResolution == 98) { pTG->SrcHiRes = 0; } else { pTG->SrcHiRes = 1; } pTG->fTiffOpenOrCreated = 1; MyDebugPrint(pTG, LOG_ALL, "Successfully opened TIFF Yres=%d HiRes=%d\n", pTG->TiffInfo.YResolution, pTG->SrcHiRes); } else { MyDebugPrint(pTG, LOG_ERR, "ERROR:tiff file %s is OPENED already\n", pTG->lpwFileName); MyDebugPrint(pTG, LOG_ERR, "ERROR:Can't open tiff file %s\n", pTG->lpwFileName); // pTG->StatusId = FS_TIFF_SRC_BAD pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } // Fax Service Callback //---------------------- if (!FaxSendCallback(FaxHandle, CallHandle, 0, 0) ) { pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } // Send the Fax //----------------------------------------------------------------------- // here we already know what Class we will use for a particular modem. //------------------------------------------------------------------- if (pTG->ModemClass == MODEM_CLASS2) { Class2Init(pTG); RetCode = T30Cl2Tx (pTG, pTG->lpszDialDestFax); } else if (pTG->ModemClass == MODEM_CLASS2_0) { Class20Init(pTG); RetCode = T30Cl20Tx (pTG, pTG->lpszDialDestFax); } else if (pTG->ModemClass == MODEM_CLASS1) { RetCode = T30Cl1Tx(pTG, pTG->lpszDialDestFax); } // delete all the files that are left _fmemcpy (pTG->InFileName, gT30.TmpDirectory, gT30.dwLengthTmpDirectory); _fmemcpy (&pTG->InFileName[gT30.dwLengthTmpDirectory], pTG->lpszPermanentLineID, 8); for (dw = pTG->CurrentIn; dw <= pTG->LastOut; dw++) { sprintf( &pTG->InFileName[gT30.dwLengthTmpDirectory+8], ".%03d", dw); if (! DeleteFileA (pTG->InFileName) ) { MyDebugPrint(pTG, LOG_ERR, "ERROR: file %s can't be deleted; le=%lx at %ld \n", pTG->InFileName, GetLastError(), GetTickCount() ); } } if (pTG->fTiffOpenOrCreated) { TiffClose( (HANDLE) pTG->Inst.hfile); pTG->fTiffOpenOrCreated = 0; } iModemClose(pTG); // release the line //----------------------------- if (pTG->fDeallocateCall == 0) { // // line never was signalled IDLE, need to lineDrop first // if (!itapi_async_setup(pTG)) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevSend: lineDrop itapi_async_setup failed \n"); if (!pTG->fFatalErrorWasSignaled) { pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); } RetCode = FALSE; goto l_exit; } lRet = lineDrop (pTG->CallHandle, NULL, 0); if (lRet < 0) { MyDebugPrint(pTG, LOG_ERR, "ERROR: lineDrop failed %lx\n", lRet); // return (FALSE); } else { MyDebugPrint(pTG, LOG_ALL, "lineDrop returns request %d\n", lRet); if(!itapi_async_wait(pTG, (DWORD)lRet, (LPDWORD)&lRet, NULL, ASYNC_SHORT_TIMEOUT)) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevSend: itapi_async_wait failed on lineDrop\n"); goto l_exit; } MyDebugPrint(pTG, LOG_ALL, "lineDrop SUCCESS\n"); } // //deallocating call // // it took us some time since first test if (pTG->fDeallocateCall == 0) { pTG->fDeallocateCall = 1; #if 0 // // this is now performed in the fax service // lRet = lineDeallocateCall(pTG->CallHandle ); if (lRet) { MyDebugPrint(pTG, LOG_ERR, "ERROR: lineDeallocateCall returns %lx\n", lRet); } else { MyDebugPrint(pTG, LOG_ALL, "lineDeallocateCall SUCCESS\n"); } #endif } } l_exit: if ( (RetCode == FALSE) && (pTG->StatusId == FS_COMPLETED) ) { MyDebugPrint(pTG, LOG_ERR, "ERROR: exit FaxDevSend success but later failed \n"); RetCode = TRUE; } if ( (RecoveryIndex >= 0) && (RecoveryIndex < MAX_T30_CONNECT) ) { T30Recovery[RecoveryIndex].fAvail = TRUE; } /// RSL -revisit, may decrease prty during computation if (! SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL) ) { MyDebugPrint(pTG, LOG_ERR, "ERROR: SetThreadPriority Normal failed le=%x", GetLastError() ); } if (pTG->InFileHandleNeedsBeClosed) { CloseHandle(pTG->InFileHandle); pTG->InFileHandleNeedsBeClosed = 0; } MemFree(FaxSend->FileName); MemFree(FaxSend->CallerName); MemFree(FaxSend->CallerNumber); MemFree(FaxSend->ReceiverName); MemFree(FaxSend->ReceiverNumber); if (!pTG->AckTerminate) { if ( WaitForSingleObject(pTG->ThrdAckTerminateSignal, TX_WAIT_ACK_TERMINATE_TIMEOUT) == WAIT_TIMEOUT ) { MyDebugPrint(pTG, LOG_ERR, "WARNING: Never got AckTerminate \n"); } } MyDebugPrint(pTG, LOG_ALL, "Got AckTerminate OK at %ld \n", GetTickCount() ); SetEvent(pTG->AbortAckEvent); MyDebugPrint(pTG, LOG_ALL, "FaxDevSendA rets %d at %ld \n", RetCode, GetTickCount() ); return (RetCode); } __except (EXCEPTION_EXECUTE_HANDLER) { // // try to use the Recovery data // DWORD dwCkSum; HCALL CallHandle; HANDLE CompletionPortHandle; ULONG_PTR CompletionKey; PThrdGlbl pTG; DWORD dwThreadId = GetCurrentThreadId(); fFound = 0; for (i=0; iInFileHandleNeedsBeClosed) { CloseHandle(pTG->InFileHandle); } SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL); return (FALSE); } } /////////////////////////////////////////////////////////////////////////////////// BOOL WINAPI FaxDevReceiveA( HANDLE FaxHandle, HCALL CallHandle, PFAX_RECEIVE_A FaxReceive ) /*++ Routine Description: Arguments: Return Value: --*/ { LONG_PTR i; PThrdGlbl pTG=NULL; long lRet; DWORD dw; LPVARSTRING lpVarStr=0; LPDEVICEID lpDeviceID=0; LPLINEDEVCAPS lpLineDevCaps; BYTE buf[ sizeof(LINEDEVCAPS)+1000 ]; LONG lResult=0; BOOL RetCode; DWORD dwNeededSize; LPDEVCFG lpDevCfg; LPMODEMSETTINGS lpModemSettings; int fFound=0; int RecoveryIndex = -1; LPMDM_DEVSPEC lpDSpec; char rgchKey[256]; HKEY hKey; DWORD dwType; DWORD dwSize; __try { MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: FaxDevReceiveA FaxHandle=%x, CallHandle=%x, FaxReceive=%x at %ld \n", FaxHandle, CallHandle, FaxReceive, GetTickCount() ); // find instance data //------------------------ i = (LONG_PTR) FaxHandle; if (i < 1 || i >= MAX_T30_CONNECT) { MemFree(FaxReceive->FileName); MemFree(FaxReceive->ReceiverName); MemFree(FaxReceive->ReceiverNumber); MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: ERROR i FaxDevReceiveA FaxHandle=%x, CallHandle=%x, FaxReceive=%x at %ld \n", FaxHandle, CallHandle, FaxReceive, GetTickCount() ); return (FALSE); } if (T30Inst[i].fAvail) { MemFree(FaxReceive->FileName); MemFree(FaxReceive->ReceiverName); MemFree(FaxReceive->ReceiverNumber); MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: ERROR AVAIL FaxDevReceiveA FaxHandle=%x, CallHandle=%x, FaxReceive=%x at %ld \n", FaxHandle, CallHandle, FaxReceive, GetTickCount() ); return (FALSE); } pTG = (PThrdGlbl) T30Inst[i].pT30; pTG->CallHandle = CallHandle; // // Add entry to the Recovery Area. // fFound = 0; for (i=0; iLineHandle; T30Recovery[i].CallHandle = CallHandle; T30Recovery[i].DeviceId = pTG->DeviceId; T30Recovery[i].CompletionPortHandle = pTG->CompletionPortHandle; T30Recovery[i].CompletionKey = pTG->CompletionKey; T30Recovery[i].TiffThreadId = 0; T30Recovery[i].TimeStart = GetTickCount(); T30Recovery[i].TimeUpdated = T30Recovery[i].TimeStart; T30Recovery[i].CkSum = ComputeCheckSum( (LPDWORD) &T30Recovery[i].fAvail, sizeof ( T30_RECOVERY_GLOB ) / sizeof (DWORD) - 1); LeaveCriticalSection(&T30RecoveryCritSection); fFound = 1; RecoveryIndex = (int)i; pTG->RecoveryIndex = (int)i; break; } } if (! fFound) { MyDebugPrint(pTG, LOG_ERR, "ERROR:Couldn't find available space for Recovery\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } pTG->Operation = T30_RX; // store LocalID if (FaxReceive->ReceiverNumber == NULL) { pTG->LocalID[0] = 0; } else { _fmemcpy(pTG->LocalID, FaxReceive->ReceiverNumber, min (_fstrlen(FaxReceive->ReceiverNumber), sizeof(pTG->LocalID) - 1) ); pTG->LocalID [ min (_fstrlen(FaxReceive->ReceiverNumber), sizeof(pTG->LocalID) - 1) ] = 0; } // tiff //----------------------------------------------- pTG->lpwFileName = AnsiStringToUnicodeString(FaxReceive->FileName); pTG->SrcHiRes = 1; // take line over from TAPI //-------------------------- pTG->fGotConnect = FALSE; // initiate passthru if (!itapi_async_setup(pTG)) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevReceive: itapi_async_setup failed \n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } lRet = lineSetCallParams(CallHandle, LINEBEARERMODE_PASSTHROUGH, 0, 0xffffffff, NULL); if (lRet < 0) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevReceive: lineSetCallParams failed \n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } else { MyDebugPrint(pTG, LOG_ALL, "lpfnlineSetCallParams returns ID %ld\n", (long) lRet); } if(!itapi_async_wait(pTG, (DWORD)lRet, &lRet, NULL, ASYNC_TIMEOUT)) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevReceive: itapi_async_wait failed \n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } // now we wait for the connected message //-------------------------------------- for (dw=50; dw<10000; dw = dw*120/100) { Sleep(dw); if (pTG->fGotConnect) break; } if (!pTG->fGotConnect) { MyDebugPrint(pTG, LOG_ERR, "ERROR:Failure waiting for CONNECTED message....\n"); // We ignore... } // get the handle to a Comm port //---------------------------------- lpVarStr = (LPVARSTRING) MemAlloc(IDVARSTRINGSIZE); if (!lpVarStr) { MyDebugPrint(pTG, LOG_ALL, "ERROR:Couldn't allocate space for lpVarStr\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } _fmemset(lpVarStr, 0, IDVARSTRINGSIZE); lpVarStr->dwTotalSize = IDVARSTRINGSIZE; MyDebugPrint(pTG, LOG_ALL, "Calling lineGetId\n"); lRet = lineGetID(pTG->LineHandle, 0, // +++ addr CallHandle, LINECALLSELECT_CALL, // dwSelect, lpVarStr, //lpDeviceID, "comm/datamodem" ); //lpszDeviceClass if (lRet) { MyDebugPrint(pTG, LOG_ERR, "ERROR:lineGetID returns error 0x%lx\n", (unsigned long) lRet); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } MyDebugPrint(pTG, LOG_ALL, "lineGetId returned SUCCESS\n"); // extract id if (lpVarStr->dwStringFormat != STRINGFORMAT_BINARY) { MyDebugPrint(pTG, LOG_ERR, "ERROR:String format is not binary\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } if (lpVarStr->dwUsedSizefFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } lpDeviceID = (LPDEVICEID) ((LPBYTE)(lpVarStr)+lpVarStr->dwStringOffset); MyDebugPrint(pTG, LOG_ALL, "lineGetID returns handle 0x%08lx, \"%s\"\n", (ULONG_PTR) lpDeviceID->hComm, (LPSTR) lpDeviceID->szDeviceName); pTG->hComm = lpDeviceID->hComm; if (BAD_HANDLE(pTG->hComm)) { MyDebugPrint(pTG, LOG_ERR, "ERROR:lineGetID returns NULL hComm\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } // get the Modem configuration (speaker, etc.) from TAPI //------------------------------------------------------ _fmemset(lpVarStr, 0, IDVARSTRINGSIZE); lpVarStr->dwTotalSize = IDVARSTRINGSIZE; lResult = lineGetDevConfig(pTG->DeviceId, lpVarStr, "comm/datamodem"); if (lResult) { if (lpVarStr->dwTotalSize < lpVarStr->dwNeededSize) { dwNeededSize = lpVarStr->dwNeededSize; MemFree (lpVarStr); if ( ! (lpVarStr = (LPVARSTRING) MemAlloc(dwNeededSize) ) ) { MyDebugPrint(pTG, LOG_ERR, "ERR: Can't allocate %d bytes for lineGetDevConfig\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } _fmemset(lpVarStr, 0, dwNeededSize); lpVarStr->dwTotalSize = dwNeededSize; lResult = lineGetDevConfig(pTG->DeviceId, lpVarStr, "comm/datamodem"); if (lResult) { MyDebugPrint(pTG, LOG_ERR, "ERR: lineGetDevConfig returns %x, le=%x", lResult, GetLastError() ); MemFree (lpVarStr); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } } else { MyDebugPrint(pTG, LOG_ERR, "ERR: 1st lineGetDevConfig returns %x, le=%x", lResult, GetLastError() ); MemFree (lpVarStr); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } } // // extract DEVCFG // if (lpVarStr->dwStringFormat != STRINGFORMAT_BINARY) { MyDebugPrint(pTG, LOG_ERR, "ERROR: String format is not binary for lineGetDevConfig\n"); MemFree (lpVarStr); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } if (lpVarStr->dwUsedSizefFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } lpDevCfg = (LPDEVCFG) ((LPBYTE)(lpVarStr)+lpVarStr->dwStringOffset); lpModemSettings = (LPMODEMSETTINGS) ( (LPBYTE) &(lpDevCfg->commconfig.wcProviderData) ); pTG->dwSpeakerVolume = lpModemSettings->dwSpeakerVolume; pTG->dwSpeakerMode = lpModemSettings->dwSpeakerMode; MyDebugPrint(pTG, LOG_ALL, "lineGetDevConfig returns SpeakerVolume=%x, Volume=%x\n", pTG->dwSpeakerVolume, pTG->dwSpeakerMode); MemFree (lpVarStr); lpVarStr=0; // get dwPermanentLineID // --------------------------- lpLineDevCaps = (LPLINEDEVCAPS) buf; _fmemset(lpLineDevCaps, 0, sizeof (buf) ); lpLineDevCaps->dwTotalSize = sizeof(buf); lResult = lineGetDevCaps(gT30.LineAppHandle, pTG->DeviceId, TAPI_VERSION, 0, lpLineDevCaps); if (lResult) { MyDebugPrint(pTG, LOG_ERR, "ERROR:lineGetDevCaps failed\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } if (lpLineDevCaps->dwNeededSize > lpLineDevCaps->dwTotalSize) { MyDebugPrint(pTG, LOG_ERR, "ERROR:lineGetDevCaps NOT enough MEMORY\n"); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } // Save the permanent ID. //------------------------ pTG->dwPermanentLineID =lpLineDevCaps->dwPermanentLineID; _stprintf (pTG->lpszPermanentLineID, "%08d\\Modem", pTG->dwPermanentLineID); MyDebugPrint(pTG, LOG_ALL, "Permanent Line ID=%s\n", pTG->lpszPermanentLineID); // Get the Unimodem key name for this device //------------------------------------------ lpDSpec = (LPMDM_DEVSPEC) ( ( (LPBYTE) lpLineDevCaps) + lpLineDevCaps->dwDevSpecificOffset); if ( (lpLineDevCaps->dwDevSpecificSize < sizeof(MDM_DEVSPEC) ) || (lpLineDevCaps->dwDevSpecificSize <= lpDSpec->dwKeyOffset) ) { MyDebugPrint(pTG, LOG_ERR, "Devspecifc caps size is only %lu", (unsigned long) lpLineDevCaps->dwDevSpecificSize ); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } else { UINT u = lpLineDevCaps->dwDevSpecificSize - lpDSpec->dwKeyOffset; #define szAPPEND "\\FAX" if ( (lpDSpec->dwContents != 1) || (lpDSpec->dwKeyOffset != 8 ) ) { MyDebugPrint(pTG, LOG_ERR, "Nonstandard Devspecific: dwContents=%lu; dwKeyOffset=%lu", (unsigned long) lpDSpec->dwContents, (unsigned long) lpDSpec->dwKeyOffset ); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } if (u) { _fmemcpy(rgchKey, lpDSpec->rgby, u); if (rgchKey[u]) { MyDebugPrint(pTG, LOG_ERR, "rgchKey not null terminated!" ); rgchKey[u-1]=0; } // // Get ResponsesKeyName value // lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, rgchKey, 0, KEY_READ, &hKey); if (lRet != ERROR_SUCCESS) { MyDebugPrint(pTG, LOG_ERR, "Can't read Unimodem key %s\n", rgchKey); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } dwSize = sizeof( pTG->ResponsesKeyName); lRet = RegQueryValueEx( hKey, "ResponsesKeyName", 0, &dwType, pTG->ResponsesKeyName, &dwSize); RegCloseKey(hKey); if (lRet != ERROR_SUCCESS) { MyDebugPrint(pTG, LOG_ERR, "Can't read Unimodem key\\ResponsesKeyName %s\n", rgchKey); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); RetCode = FALSE; goto l_exit; } // Append "\\Fax" to the key u = lstrlen(rgchKey); if (u) { lstrcpy(rgchKey+u, (LPSTR) szAPPEND); } lstrcpy(pTG->lpszUnimodemFaxKey, rgchKey); MyDebugPrint(pTG, LOG_ALL, "Unimodem Fax key=%s\n", pTG->lpszUnimodemFaxKey); } } /// RSL -revisit, may decrease prty during computation if (! SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) ) { MyDebugPrint(pTG, LOG_ERR, "ERROR: SetThreadPriority TIME CRITICAL failed le=%x", GetLastError() ); } // initialize modem //-------------------- T30ModemInit(pTG, pTG->hComm, 0, LINEID_TAPI_PERMANENT_DEVICEID, DEF_BASEKEY, pTG->lpszPermanentLineID, fMDMINIT_ANSWER); pTG->Inst.ProtParams.uMinScan = MINSCAN_0_0_0; ET30ProtSetProtParams(pTG, &pTG->Inst.ProtParams, pTG->FComModem.CurrMdmCaps.uSendSpeeds, pTG->FComModem.CurrMdmCaps.uRecvSpeeds); InitCapsBC( pTG, (LPBC) &pTG->Inst.SendCaps, sizeof(pTG->Inst.SendCaps), SEND_CAPS); // answer the call and receive a fax //----------------------------------- // here we already know what Class we will use for a particular modem. //------------------------------------------------------------------- if (pTG->ModemClass == MODEM_CLASS2) { Class2Init(pTG); RetCode = T30Cl2Rx (pTG); } else if (pTG->ModemClass == MODEM_CLASS2_0) { Class20Init(pTG); RetCode = T30Cl20Rx (pTG); } else if (pTG->ModemClass == MODEM_CLASS1) { RetCode = T30Cl1Rx(pTG); } if ( pTG->fTiffOpenOrCreated ) { TiffClose( (HANDLE) pTG->Inst.hfile ); pTG->fTiffOpenOrCreated = 0; } iModemClose(pTG); #ifdef ADAPTIVE_ANSWER if (pTG->Comm.fEnableHandoff && pTG->Comm.fDataCall) { MyDebugPrint(pTG, LOG_ALL, "DataCall dont hangup\n"); RetCode = FALSE; goto l_exit; } #endif // release the line //----------------------------- if (pTG->fDeallocateCall == 0) { // // line never was signalled IDLE, need to lineDrop first // if (!itapi_async_setup(pTG)) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevReceive: lineDrop itapi_async_setup failed \n"); if (!pTG->fFatalErrorWasSignaled) { pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); } RetCode = FALSE; goto l_exit; } lRet = lineDrop (pTG->CallHandle, NULL, 0); if (lRet < 0) { MyDebugPrint(pTG, LOG_ERR, "ERROR: lineDrop failed %lx\n", lRet); if (!pTG->fFatalErrorWasSignaled) { pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_FATAL_ERROR); } RetCode = FALSE; goto l_exit; } else { MyDebugPrint(pTG, LOG_ALL, "lineDrop returns request %d\n", lRet); } if(!itapi_async_wait(pTG, (DWORD)lRet, &lRet, NULL, ASYNC_SHORT_TIMEOUT)) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevReceive: itapi_async_wait failed on lineDrop\n"); goto l_exit; } MyDebugPrint(pTG, LOG_ALL, "lineDrop SUCCESS\n"); // //deallocating call // if (pTG->fDeallocateCall == 0) { pTG->fDeallocateCall = 1; #if 0 // // this is now performed in the fax service // lRet = lineDeallocateCall(pTG->CallHandle ); if (lRet) { MyDebugPrint(pTG, LOG_ERR, "ERROR: lineDeallocateCall returns %lx\n", lRet); } else { MyDebugPrint(pTG, LOG_ALL, "lineDeallocateCall SUCCESS\n"); } #endif } } l_exit: if ( (RetCode == FALSE) && (pTG->StatusId == FS_COMPLETED) ) { MyDebugPrint(pTG, LOG_ERR, "ERROR: exit FaxDevReceive success but later failed \n"); RetCode = TRUE; } if ( (RecoveryIndex >= 0) && (RecoveryIndex < MAX_T30_CONNECT) ) { T30Recovery[RecoveryIndex].fAvail = TRUE; } if (! SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL) ) { MyDebugPrint(pTG, LOG_ERR, "ERROR: SetThreadPriority Normal failed le=%x", GetLastError() ); } if (pTG->InFileHandleNeedsBeClosed) { CloseHandle(pTG->InFileHandle); pTG->InFileHandleNeedsBeClosed = 0; } if (!pTG->AckTerminate) { if ( WaitForSingleObject(pTG->ThrdAckTerminateSignal, RX_WAIT_ACK_TERMINATE_TIMEOUT) == WAIT_TIMEOUT ) { MyDebugPrint(pTG, LOG_ERR, "WARNING: Never got AckTerminate \n"); } } MyDebugPrint(pTG, LOG_ALL, "Got AckTerminate OK at %ld \n", GetTickCount() ); SetEvent(pTG->AbortAckEvent); MemFree(FaxReceive->FileName); MemFree(FaxReceive->ReceiverName); MemFree(FaxReceive->ReceiverNumber); MyDebugPrint(pTG, LOG_ALL, "FaxDevReceiveA rets %d at %ld \n", RetCode, GetTickCount() ); return (RetCode); } __except (EXCEPTION_EXECUTE_HANDLER) { // // try to use the Recovery data // DWORD dwCkSum; HCALL CallHandle; HANDLE CompletionPortHandle; ULONG_PTR CompletionKey; PThrdGlbl pTG; DWORD dwThreadId = GetCurrentThreadId(); fFound = 0; for (i=0; iInFileHandleNeedsBeClosed) { CloseHandle(pTG->InFileHandle); } SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL); return (FALSE); } } /////////////////////////////////////////////////////////////////////////////////// BOOL WINAPI FaxDevReportStatusA( IN HANDLE FaxHandle OPTIONAL, OUT PFAX_DEV_STATUS FaxStatus, IN DWORD FaxStatusSize, OUT LPDWORD FaxStatusSizeRequired ) /*++ Routine Description: Arguments: Return Value: --*/ { LONG_PTR i; PThrdGlbl pTG; LPWSTR lpwCSI; // inside the FaxStatus struct. LPBYTE lpTemp; *FaxStatusSizeRequired = sizeof (FAX_DEV_STATUS); __try { if (FaxStatusSize < *FaxStatusSizeRequired ) { MyDebugPrint(0, LOG_ALL, "EP: WARNING:FaxDevReportStatus: wrong size passed=%d, expected not less than %d\n", FaxStatusSize, *FaxStatusSizeRequired); goto failure; } if (FaxHandle == NULL) { // means global status MyDebugPrint(0, LOG_ERR, "EP: FaxDevReportStatus NULL FaxHandle; gT30.Status=%d \n", gT30.Status); if (gT30.Status == STATUS_FAIL) { goto failure; } else { return (TRUE); } } else { // find instance data //------------------------ i = (LONG_PTR) FaxHandle; if (i < 1 || i >= MAX_T30_CONNECT) { MyDebugPrint(0, LOG_ERR, "EP: ERROR:FaxDevReportStatus - got wrong FaxHandle=%d\n", i); goto failure; } if (T30Inst[i].fAvail) { MyDebugPrint(0, LOG_ERR, "EP: ERROR:FaxDevReportStatus - got wrong FaxHandle (marked as free) %d\n", i); goto failure; } pTG = (PThrdGlbl) T30Inst[i].pT30; FaxStatus->StatusId = pTG->StatusId; FaxStatus->StringId = pTG->StringId; FaxStatus->PageCount = pTG->PageCount; if (pTG->fRemoteIdAvail) { lpTemp = (LPBYTE) FaxStatus; lpTemp += sizeof(FAX_DEV_STATUS); lpwCSI = (LPWSTR) lpTemp; wcscpy(lpwCSI, pTG->RemoteID); FaxStatus->CSI = (LPWSTR) lpwCSI; } else { FaxStatus->CSI = NULL; } FaxStatus->CallerId = NULL; // (char *) AnsiStringToUnicodeString(pTG->CallerId); FaxStatus->RoutingInfo = NULL; // (char *) AnsiStringToUnicodeString(pTG->RoutingInfo); MyDebugPrint(pTG, LOG_ALL, "EP: FaxDevReportStatus rets %lx \n", pTG->StatusId); return (TRUE); } } __except (EXCEPTION_EXECUTE_HANDLER) { MyDebugPrint(0, LOG_ERR, "EP: ERROR:FaxDevReportStatus crashed accessing data\n"); return (FALSE); } MyDebugPrint(0, LOG_ERR, "EP: ERROR:FaxDevReportStatus wrong return\n"); return (TRUE); failure: return (FALSE); } /////////////////////////////////////////////////////////////////////////////////// BOOL WINAPI FaxDevAbortOperationA( HANDLE FaxHandle ) /*++ Routine Description: Arguments: Return Value: --*/ { LONG_PTR i; PThrdGlbl pTG=NULL; long lRet; MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: FaxDevAbortOperationA FaxHandle=%x at %ld \n", FaxHandle, GetTickCount() ); // find instance data //------------------------ i = (LONG_PTR) FaxHandle; if (i < 1 || i >= MAX_T30_CONNECT) { MyDebugPrint(pTG, LOG_ERR, "FaxDevAbort - got wrong FaxHandle=%d\n", i); return (FALSE); } if (T30Inst[i].fAvail) { MyDebugPrint(pTG, LOG_ERR, "FaxDevAbort - got wrong FaxHandle (marked as free) %d\n", i); return (FALSE); } pTG = (PThrdGlbl) T30Inst[i].pT30; if (pTG->fAbortRequested) { MyDebugPrint(pTG, LOG_ERR, "FaxDevAbort - ABORT request had been POSTED already\n"); return (FALSE); } if (pTG->StatusId == FS_NOT_FAX_CALL) { MyDebugPrint( pTG, LOG_ALL, "Abort on DATA call at %ld\n", GetTickCount() ); if (!itapi_async_setup(pTG)) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevAbortOperationA: itapi_async_setup failed \n"); return (FALSE); } lRet = lineDrop(pTG->CallHandle, NULL, 0); if (lRet < 0) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevAbortOperationA: lineDrop failed %x \n", lRet); return (FALSE); } if( !itapi_async_wait(pTG, (DWORD)lRet, (LPDWORD)&lRet, NULL, ASYNC_TIMEOUT)) { MyDebugPrint(pTG, LOG_ERR, "ERROR: FaxDevAbortOperationA: async_wait lineDrop failed at %ld \n", GetTickCount() ); return (FALSE); } MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: FaxDevAbortOperationA finished SUCCESS \n"); return (TRUE); } // // real ABORT request. // MyDebugPrint( pTG, LOG_ALL, "FaxDevAbort: ABORT requested %ld\n", GetTickCount() ); pTG->fFatalErrorWasSignaled = 1; SignalStatusChange(pTG, FS_USER_ABORT); // set the global abort flag for pTG pTG->fAbortRequested = 1; // set the abort flag for imaging threads pTG->ReqTerminate = 1; // signal manual-reset event to everybody waiting on multiple objects if (! SetEvent(pTG->AbortReqEvent) ) { MyDebugPrint(pTG, LOG_ERR, "FaxDevAbort -SetEvent FAILED le=%lx at %ld\n", GetLastError(), GetTickCount() ); } // check to see whether pTG gracefully and timely shut itself down if ( WaitForSingleObject(pTG->AbortAckEvent, ABORT_ACK_TIMEOUT) == ABORT_ACK_TIMEOUT ) { MyDebugPrint(pTG, LOG_ERR, "FaxDevAbort - ABORT ACK timeout at %ld\n", GetTickCount() ); return (FALSE); } MyDebugPrint(pTG, LOG_ALL, "FaxDevAbort - ABORT ACK at %ld\n", GetTickCount() ); MyDebugPrint( (PThrdGlbl) 0, LOG_ALL, "EP: FaxDevAbortOperationA finished SUCCESS at %ld \n", GetTickCount() ); return (TRUE); }