/*++

Copyright (c) 1997 Microsoft Corporation

Module Name:

  events.c

Abstract:

  This module:
    1) Determines if the port is valid
    2) Post a completion packet to a completion port.  This packet indicates for the Fax Event Queue thread to exit.
    3) Thread to handle the Fax Event Queue logic

Author:

  Steven Kehrli (steveke) 11/15/1997

--*/

#ifndef _EVENTS_C
#define _EVENTS_C

BOOL
fnIsPortValid(
    PFAX_PORT_INFO  pFaxPortsConfig,
    DWORD           dwNumPorts,
    DWORD           dwDeviceId
)
/*++

Routine Description:

  Determines if the port is valid

Arguments:

  pFaxPortsConfig - pointer to the ports configuration
  dwNumFaxPorts - number of ports
  dwDeviceId - port id

Return Value:

  TRUE on success

--*/
{
    // dwIndex is a counter to enumerate each port
    DWORD  dwIndex;

    for (dwIndex = 0; dwIndex < dwNumPorts; dwIndex++) {
        // Search, by priority, each port for the appropriate port
        if (pFaxPortsConfig[dwIndex].DeviceId == dwDeviceId) {
            return TRUE;
        }
    }

    return FALSE;
}

VOID
fnPostExitToCompletionPort(
    HANDLE  hCompletionPort
)
/*++

Routine Description:

  Post a completion packet to a completion port.  This packet indicates for the Fax Event Queue thread to exit.

Arguments:

  hCompletionPort - handle to the completion port

Return Value:

  None

--*/
{
    PFAX_EVENT  pFaxEvent;

    pFaxEvent = LocalAlloc(LPTR, sizeof(FAX_EVENT));
    pFaxEvent->EventId = -1;

    PostQueuedCompletionStatus(hCompletionPort, sizeof(FAX_EVENT), 0, (LPOVERLAPPED) pFaxEvent);
}

DWORD WINAPI fnFaxEventQueueProc (LPVOID lpv)
/*++

Routine Description:

  Thread to handle the Fax Event Queue logic

Return Value:

  DWORD - exit code

--*/
{
    // pFaxEvent is a pointer to the port event
    PFAX_EVENT        pFaxEvent;
    DWORD             dwBytes;
    UINT_PTR          upCompletionKey;

    // FaxDialingInfo is the fax dialing info
    FAX_DIALING_INFO  FaxDialingInfo;

    // bFaxPassed indicates a fax passed
    BOOL              bFaxPassed = FALSE;
    // bFaxFailed indicates a fax failed
    BOOL              bFaxFailed = FALSE;
    // dwDeviceId is the port id
    DWORD             dwDeviceId = 0;

    while (GetQueuedCompletionStatus(g_hCompletionPort, &dwBytes, &upCompletionKey, (LPOVERLAPPED *) &pFaxEvent, INFINITE)) {

        if (pFaxEvent->EventId == -1) {
            // g_hExitEvent was signaled, so thread should exit
            LocalFree(pFaxEvent);
            break;
        }

        if (pFaxEvent->EventId == FEI_FAXSVC_ENDED) {
            // Signal the g_hFaxEvent
            SetEvent(g_hFaxEvent);

            // Free the packet
            LocalFree(pFaxEvent);
            break;
        }

        if (pFaxEvent->EventId == FEI_MODEM_POWERED_OFF) {
            // Update the status
            SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_DEVICE_POWERED_OFF, pFaxEvent->DeviceId);

            // Free the packet
            LocalFree(pFaxEvent);

            // Decrement g_dwNumAvailPorts
            g_dwNumAvailPorts--;
            if (!g_dwNumAvailPorts) {
                SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_PORTS_NOT_AVAILABLE, 0);
            }
            continue;
        }

        if (pFaxEvent->EventId == FEI_MODEM_POWERED_ON) {
            // Update the status
            SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_DEVICE_POWERED_ON, pFaxEvent->DeviceId);

            // Free the packet
            LocalFree(pFaxEvent);

            // Increment g_dwNumAvailPorts
            g_dwNumAvailPorts++;
            continue;
        }

        // Verify the port is valid
        if (!fnIsPortValid(g_pFaxPortsConfig, g_dwNumPorts, pFaxEvent->DeviceId)) {
            // Free the packet
            LocalFree(pFaxEvent);
            continue;
        }

        if ((pFaxEvent->EventId == FEI_IDLE) && (g_bFaxSndInProgress) && (pFaxEvent->DeviceId == dwDeviceId) && ((bFaxPassed) || (bFaxFailed))) {
            // Update the status
            SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_IDLE, pFaxEvent->DeviceId);
            if (bFaxPassed) {
                SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_SEND_PASSED, pFaxEvent->DeviceId);
                // Signal the Send Passed event
                SetEvent(g_hSendPassedEvent);
            }
            else {
                SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_SEND_FAILED, pFaxEvent->DeviceId);
                // Signal the Send Failed event
                SetEvent(g_hSendFailedEvent);
            }
            dwDeviceId = 0;
            bFaxPassed = FALSE;
            bFaxFailed = FALSE;
            continue;
        }

        if ((pFaxEvent->EventId == FEI_IDLE) && (g_bFaxSndInProgress)) {
            // Update the status
            SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_IDLE, pFaxEvent->DeviceId);
        }

        if ((pFaxEvent->JobId == g_dwFaxId) && (g_bFaxSndInProgress)) {
            switch (pFaxEvent->EventId) {
                case FEI_INITIALIZING:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_INITIALIZING, pFaxEvent->DeviceId);
                    break;

                case FEI_DIALING:
                    g_dwAttempt++;
                    // Set FaxDialingInfo
                    FaxDialingInfo.dwAttempt = g_dwAttempt;
                    FaxDialingInfo.dwDeviceId = pFaxEvent->DeviceId;
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_DIALING, (LPARAM) &FaxDialingInfo);
                    dwDeviceId = pFaxEvent->DeviceId;
                    break;

                case FEI_NO_DIAL_TONE:
                    if (g_dwAttempt < (FAXSVC_RETRIES + 1)) {
                        // Update the status
                        SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_NO_DIAL_TONE_RETRY, pFaxEvent->DeviceId);
                    }
                    else {
                        // Update the status
                        SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_NO_DIAL_TONE_ABORT, pFaxEvent->DeviceId);
                        bFaxFailed = TRUE;
                    }
                    break;

                case FEI_BUSY:
                    if (g_dwAttempt < (FAXSVC_RETRIES + 1)) {
                        // Update the status
                        SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_BUSY_RETRY, pFaxEvent->DeviceId);
                    }
                    else {
                        // Update the status
                        SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_BUSY_ABORT, pFaxEvent->DeviceId);
                        bFaxFailed = TRUE;
                    }
                    break;

                case FEI_NO_ANSWER:
                    if (g_dwAttempt < (FAXSVC_RETRIES + 1)) {
                        // Update the status
                        SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_NO_ANSWER_RETRY, pFaxEvent->DeviceId);
                    }
                    else {
                        // Update the status
                        SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_NO_ANSWER_ABORT, pFaxEvent->DeviceId);
                        bFaxFailed = TRUE;
                    }
                    break;

                case FEI_SENDING:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_SENDING, pFaxEvent->DeviceId);
                    break;

                case FEI_FATAL_ERROR:
                    if (g_dwAttempt < (FAXSVC_RETRIES + 1)) {
                        // Update the status
                        SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_FATAL_ERROR_RETRY, pFaxEvent->DeviceId);
                    }
                    else {
                        // Update the status
                        SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_FATAL_ERROR_ABORT, pFaxEvent->DeviceId);
                        bFaxFailed = TRUE;
                    }
                    break;

                case FEI_ABORTING:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_ABORTING, pFaxEvent->DeviceId);
                    bFaxFailed = TRUE;
                    break;

                case FEI_COMPLETED:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_COMPLETED, pFaxEvent->DeviceId);
                    bFaxPassed = TRUE;
                    break;

                default:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_UNEXPECTED_STATE, pFaxEvent->DeviceId);
                    bFaxFailed = TRUE;
                    break;
            }
        }

        if (g_bFaxRcvInProgress) {
            switch (pFaxEvent->EventId) {
                case FEI_INITIALIZING:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_INITIALIZING, pFaxEvent->DeviceId);
                    break;

                case FEI_RINGING:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_RINGING, pFaxEvent->DeviceId);
                    break;

                case FEI_ANSWERED:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_ANSWERED, pFaxEvent->DeviceId);
                    break;

                case FEI_NOT_FAX_CALL:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_NOT_FAX_CALL, pFaxEvent->DeviceId);
                    break;

                case FEI_RECEIVING:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_RECEIVING, pFaxEvent->DeviceId);
                    break;

                case FEI_FATAL_ERROR:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_FATAL_ERROR, pFaxEvent->DeviceId);
                    break;

                case FEI_ABORTING:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_ABORTING, pFaxEvent->DeviceId);
                    break;

                case FEI_COMPLETED:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_COMPLETED, pFaxEvent->DeviceId);
                    break;

                case FEI_IDLE:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_FAX_IDLE, pFaxEvent->DeviceId);
                    break;

                default:
                    // Update the status
                    SendMessage(g_hWndDlg, UM_UPDATE_STATUS, IDS_STATUS_UNEXPECTED_STATE, pFaxEvent->DeviceId);
                    break;
            }
        }

        // Free the packet
        LocalFree(pFaxEvent);
    }

    return 0;
}

#endif