/*++ Copyright (c) 1996 Microsoft Corporation Module Name: t30util.c Abstract: Utilities for t30 Author: Rafael Lisitsa (RafaelL) 2-Feb-1996 Revision History: --*/ #define USE_DEBUG_CONTEXT DEBUG_CONTEXT_T30_MAIN #include "prep.h" #include "glbproto.h" #include "t30gl.h" #define IDVARSTRINGSIZE (sizeof(VARSTRING)+128) /////////////////////////////////////////////////////////////////////////////////// PVOID T30AllocThreadGlobalData(VOID) { PVOID pTG; pTG = MemAlloc (sizeof(ThrdGlbl) ); if(NULL != pTG) { FillMemory (pTG, sizeof(ThrdGlbl), 0); } return (pTG); } ///////////////////////////////////////////////////////////// BOOL itapi_async_setup(PThrdGlbl pTG) { BOOL bRetVal = TRUE; DEBUG_FUNCTION_NAME(_T("itapi_async_setup")); EnterCriticalSection(&T30CritSection); if (pTG->fWaitingForEvent) { DebugPrintEx(DEBUG_ERR,"Already waiting for event!"); } if (pTG->dwSignalledRID) { DebugPrintEx( DEBUG_ERR, "Nonzero old NONZERO ID 0x%lx", (unsigned long) pTG->dwSignalledRID); } pTG->fWaitingForEvent=TRUE; if (!ResetEvent(pTG->hevAsync)) { DebugPrintEx( DEBUG_ERR, "ResetEvent(0x%lx) returns failure code: %ld", (ULONG_PTR)pTG->hevAsync, (long) GetLastError()); bRetVal = FALSE; } LeaveCriticalSection(&T30CritSection); return bRetVal; } // This function wait till tapi will send message LINE_REPLY. // dwRequestID - The request we want to get reply for BOOL itapi_async_wait ( PThrdGlbl pTG, DWORD dwRequestID, PDWORD lpdwParam2, PDWORD_PTR lpdwParam3, DWORD dwTimeout ) { DWORD NumHandles=2; HANDLE HandlesArray[2]; DWORD WaitResult; DEBUG_FUNCTION_NAME(("itapi_async_wait")); if (!pTG->fWaitingForEvent) { DebugPrintEx(DEBUG_ERR,"Not waiting for event!"); // ASSERT(FALSE); // There are always time-outs that will take us out of here } HandlesArray[1] = pTG->AbortReqEvent; // // We want to be able to un-block ONCE only from waiting on I/O when the AbortReqEvent is signaled. // if (pTG->fAbortRequested) { if (pTG->fOkToResetAbortReqEvent && (!pTG->fAbortReqEventWasReset)) { DebugPrintEx(DEBUG_MSG,"RESETTING AbortReqEvent"); pTG->fAbortReqEventWasReset = TRUE; if (!ResetEvent(pTG->AbortReqEvent)) { DebugPrintEx( DEBUG_ERR, "ResetEvent(0x%lx) returns failure code: %ld", (ULONG_PTR)pTG->AbortReqEvent, (long) GetLastError()); } } pTG->fUnblockIO = TRUE; } HandlesArray[0] = pTG->hevAsync; NumHandles = 1; WaitResult = WaitForMultipleObjects(NumHandles, HandlesArray, FALSE, dwTimeout); if (WaitResult == WAIT_FAILED) { DebugPrintEx( DEBUG_ERR, "WaitForMultipleObjects FAILED le=%lx", GetLastError()); } switch( WaitResult ) { case (WAIT_OBJECT_0): { // This happen when TAPI send LINE_REPLY. (The working thread call itapi_async_signal) BOOL fRet=TRUE; EnterCriticalSection(&T30CritSection); // Check that the Request ID we got is the ID we are waiting for if(pTG->dwSignalledRID == dwRequestID) { pTG->dwSignalledRID = 0; pTG->fWaitingForEvent = FALSE; } else { DebugPrintEx( DEBUG_ERR, "Request ID mismatch. Input:0x%p; Curent:0x%p", dwRequestID, pTG->dwSignalledRID); fRet=FALSE; } LeaveCriticalSection(&T30CritSection); if (!fRet) goto failure; } break; case WAIT_TIMEOUT: DebugPrintEx( DEBUG_ERR, "Wait timed out. RequestID=0x%p", dwRequestID); goto failure; default: DebugPrintEx( DEBUG_ERR, "Wait returns error. GetLastError=%ld", (long) GetLastError()); goto failure; } if (lpdwParam2) *lpdwParam2 = pTG->dwSignalledParam2; if (lpdwParam3) *lpdwParam3 = pTG->dwSignalledParam3; return TRUE; failure: EnterCriticalSection(&T30CritSection); if(pTG->dwSignalledRID==dwRequestID) { pTG->dwSignalledRID=0; pTG->fWaitingForEvent=FALSE; } LeaveCriticalSection(&T30CritSection); return FALSE; } BOOL itapi_async_signal ( PThrdGlbl pTG, DWORD dwRequestID, DWORD dwParam2, DWORD_PTR dwParam3 ) { BOOL fRet=FALSE; DEBUG_FUNCTION_NAME(_T("itapi_async_signal")); EnterCriticalSection(&T30CritSection); if (!pTG->fWaitingForEvent) { DebugPrintEx( DEBUG_ERR, "Not waiting for event, ignoring ID=0x%lx", (unsigned long) dwRequestID); goto end; } if (pTG->dwSignalledRID) { DebugPrintEx( DEBUG_ERR, "Nonzero old NONZERO ID 0x%lx. New ID=0x%lx", (unsigned long) pTG->dwSignalledRID, (unsigned long) dwRequestID); } pTG->dwSignalledRID=dwRequestID; pTG->dwSignalledParam2= 0; pTG->dwSignalledParam3= 0; if (!SetEvent(pTG->hevAsync)) { DebugPrintEx( DEBUG_ERR, "SetEvent(0x%lx) returns failure code: %ld", (ULONG_PTR) pTG->hevAsync, (long) GetLastError()); fRet=FALSE; goto end; } pTG->dwSignalledParam2= dwParam2; pTG->dwSignalledParam3= dwParam3; fRet=TRUE; end: LeaveCriticalSection(&T30CritSection); return fRet; } #define CALLPARAMS_SIZE (sizeof(LINECALLPARAMS)+512) LPLINECALLPARAMS itapi_create_linecallparams(void) { UINT cb = CALLPARAMS_SIZE; LPLINECALLPARAMS lpParams = MemAlloc(cb); if (!lpParams) goto end; _fmemset(lpParams,0, cb); lpParams->dwTotalSize= cb; lpParams->dwBearerMode = LINEBEARERMODE_PASSTHROUGH; lpParams->dwMediaMode = LINEMEDIAMODE_DATAMODEM; // Unimodem only accepts lpParams->dwCallParamFlags = 0; lpParams->dwAddressMode = LINEADDRESSMODE_ADDRESSID; lpParams->dwAddressID = 0; // +++ assumes addreddid 0. lpParams->dwCalledPartySize = 0; // +++ lpParams->dwCalledPartyOffset = 0; // +++ end: return lpParams; } BOOL SignalStatusChange ( PThrdGlbl pTG, DWORD StatusId ) { FAX_DEV_STATUS *pFaxStatus = NULL; LPWSTR lpwCSI; // inside the FaxStatus struct. LPBYTE lpTemp; LPWSTR lpwCallerId = NULL; DEBUG_FUNCTION_NAME(_T("SignalStatusChange")); // // If Aborting OR completed then do NOT override the statusId // if ( (pTG->StatusId == FS_USER_ABORT) || (pTG->StatusId == FS_COMPLETED)) { // allow changing the status from FS_****_ABORT to FS_COMPLETED only if (StatusId!=FS_COMPLETED) { return (TRUE); } } pTG->StatusId = StatusId; // should use HeapAlloc because FaxSvc frees it. pFaxStatus = HeapAlloc(gT30.HeapHandle , HEAP_ZERO_MEMORY, sizeof(FAX_DEV_STATUS) + 4096 ); if (!pFaxStatus) { DebugPrintEx(DEBUG_ERR, "SignalStatusChange HeapAlloc failed"); goto failure; } pFaxStatus->SizeOfStruct = sizeof (FAX_DEV_STATUS); pFaxStatus->StatusId = pTG->StatusId; pFaxStatus->StringId = pTG->StringId; if (pTG->StatusId == FS_RECEIVING) { pFaxStatus->PageCount = pTG->PageCount + 1; } else { pFaxStatus->PageCount = pTG->PageCount; } lpTemp = (LPBYTE) pFaxStatus; lpTemp += sizeof(FAX_DEV_STATUS); if (pTG->fRemoteIdAvail) { lpwCSI = (LPWSTR) lpTemp; wcscpy(lpwCSI, pTG->RemoteID); pFaxStatus->CSI = (LPWSTR) lpwCSI; lpTemp += ((wcslen(pFaxStatus->CSI)+1)*sizeof(WCHAR)); } else { pFaxStatus->CSI = NULL; } pFaxStatus->CallerId = (LPWSTR) lpTemp; lpwCallerId = (LPWSTR) AnsiStringToUnicodeString(pTG->CallerId); if (lpwCallerId) { wcscpy(pFaxStatus->CallerId, lpwCallerId); MemFree(lpwCallerId); } else { pFaxStatus->CallerId = NULL; } // do we want to put something here? currently there's no support for Routing Info. pFaxStatus->RoutingInfo = NULL; if (! PostQueuedCompletionStatus(pTG->CompletionPortHandle, sizeof (FAX_DEV_STATUS), pTG->CompletionKey, (LPOVERLAPPED) pFaxStatus) ) { DebugPrintEx( DEBUG_ERR, "PostQueuedCompletionStatus failed LE=%x", GetLastError()); goto failure; } DebugPrintEx( DEBUG_MSG, "ID=%x Page=%d", pTG->StatusId, pTG->PageCount); return (TRUE); failure: if (pFaxStatus) { HeapFree(gT30.HeapHandle,0,pFaxStatus); } return (FALSE); } BOOL SignalStatusChangeWithStringId ( PThrdGlbl pTG, DWORD StatusId, DWORD StringId ) { pTG->StringId = StringId; return SignalStatusChange(pTG, StatusId); } BOOL SignalRecoveryStatusChange ( T30_RECOVERY_GLOB *Recovery ) { FAX_DEV_STATUS *pFaxStatus = NULL; // should use HeapAlloc because FaxSvc frees it. pFaxStatus = HeapAlloc(gT30.HeapHandle , HEAP_ZERO_MEMORY, sizeof(FAX_DEV_STATUS) + 4096 ); if (!pFaxStatus) { goto failure; } pFaxStatus->SizeOfStruct = sizeof (FAX_DEV_STATUS) + 4096; pFaxStatus->StatusId = FS_FATAL_ERROR; // RSL better: FS_FSP_EXCEPTION_HANDLED; pFaxStatus->StringId = 0; pFaxStatus->PageCount = 0; pFaxStatus->CSI = NULL; pFaxStatus->CallerId = NULL; pFaxStatus->RoutingInfo = NULL; if (! PostQueuedCompletionStatus(Recovery->CompletionPortHandle, sizeof (FAX_DEV_STATUS), Recovery->CompletionKey, (LPOVERLAPPED) pFaxStatus) ) { goto failure; } return (TRUE); failure: if (pFaxStatus) { HeapFree(gT30.HeapHandle,0,pFaxStatus); } return (FALSE); } DWORD ComputeCheckSum ( LPDWORD BaseAddr, DWORD NumDwords ) { DWORD RetValue = 0; DWORD i; for (i=0; i=actionNUM_ACTIONS) return NULL; return sgActionDescriptionTable[action]; } static LPCTSTR sgEventDescriptionTable[eventNUM_EVENTS] = { "eventNULL", "eventGOTFRAMES", "eventNODE_A", "eventSENDDCS", "eventGOTFTT", "eventGOTCFR", "eventSTARTSEND", "eventPOSTPAGE", "eventGOTPOSTPAGERESP", "eventGOT_ECM_PPS_RESP", "eventSENDDIS", "eventSENDDTC", "eventRECVCMD", "eventGOTTCF", "eventSTARTRECV", "eventRECVPOSTPAGECMD", "eventECM_POSTPAGE", "event4THPPR", "eventNODE_T", "eventNODE_R", }; LPCTSTR event_GetEventDescription(ET30EVENT event) { Assert(event=eventNUM_EVENTS) return NULL; return sgEventDescriptionTable[event]; } static LPCTSTR sgIfrDescriptionTable[] = { "ifrNULL", "ifrDIS", "ifrCSI", "ifrNSF", "ifrDTC", "ifrCIG", "ifrNSC", "ifrDCS", "ifrTSI", "ifrNSS", "ifrCFR", "ifrFTT", "ifrMPS", "ifrEOM", "ifrEOP", "ifrPWD", "ifrSEP", "ifrSUB", "ifrMCF", "ifrRTP", "ifrRTN", "ifrPIP", "ifrPIN", "ifrDCN", "ifrCRP", "ifrPRI_MPS", "ifrPRI_EOM", "ifrPRI_EOP", "ifrCTC", "ifrCTR", "ifrRR", "ifrPPR", "ifrRNR", "ifrERR", "ifrPPS_NULL", "ifrPPS_MPS", "ifrPPS_EOM", "ifrPPS_EOP", "ifrPPS_PRI_MPS", "ifrPPS_PRI_EOM", "ifrPPS_PRI_EOP", "ifrEOR_NULL", "ifrEOR_MPS", "ifrEOR_EOM", "ifrEOR_EOP", "ifrEOR_PRI_MPS", "ifrEOR_PRI_EOM", "ifrEOR_PRI_EOP", "ifrMAX", "ifrBAD", "ifrTIMEOUT", }; static const int ifrNUM_IFR = sizeof(sgIfrDescriptionTable)/sizeof(sgIfrDescriptionTable[0]); LPCTSTR ifr_GetIfrDescription(BYTE ifr) { Assert(ifr<=ifrNUM_IFR); if (ifr>ifrNUM_IFR) return NULL; return sgIfrDescriptionTable[ifr]; }