Figure 6   MYTAPI_.C

 #include "comdial.h"
#include "resource.h"


extern HWND hTTYWnd;

/////////////////////////////////////////////////////////////////////
//    telephonyInitialize - mega function to retrieve all 
//        configuration information needed for telephony, plus
//        initialize TAPI and open the line.
////////////////////////////////////////////////////////////////////
int telephonyInitialize(HWND hWnd, HINSTANCE hInst, PMYTAPI mytapi)
{
    LONG lrc;
    int i;
    LINEEXTENSIONID extensions;

    // initialize application use of TAPI
    while (lineInitialize(&mytapi->hTAPI, hInst, 
            mytapi->CallbackProc = (LINECALLBACK)MakeProcInstance((FARPROC)LineCallBackProc, 
                               hInst),
                               "TAPIProcess", &mytapi->dwNumLines) ==
                               LINEERR_REINIT) {
        Sleep (5);            // sleep for five seconds
        if (MessageBox(hWnd, "Telephony system is reinitializing - Click" \
                      " Cancel to abort", "Error", MB_RETRYCANCEL) ==IDCANCEL)
            goto error;
    } // end while (TAPI reinitializing)

    // bool indicates lineInitialize called successfully
    mytapi->bInitialized = TRUE;

    // check every logical line for one that support modem data
    for (i=0; (unsigned)i<mytapi->dwNumLines; i++) {

        // negotiate version of TAPI to use
        lrc = lineNegotiateAPIVersion(mytapi->hTAPI, i, WIN95TAPIVERSION,
                                      WIN95TAPIVERSION, &mytapi->dwVersionToUse,
                                      &extensions);
        if (lrc)
            continue;
        
        // get line device caps
        lrc = mylineGetDevCaps (mytapi);
        if (lrc)
            goto error;

        // check that the line supports answering machines
        if (mytapi->pLinedevcaps->dwMediaModes & LINEMEDIAMODE_AUTOMATEDVOICE) {
            mytapi->dwLine = i;
            break;
        }

    }        


    return 0;

error:
    // error!  clean up and return error code

    telephonyShutdown(mytapi);

    return lrc;

}
/////////////////////////////////////////////////////////////////////
//    telephonyOpen - open the telephone line device
//
////////////////////////////////////////////////////////////////////
int telephonyOpen(HWND hWnd, HINSTANCE hInst, PMYTAPI mytapi)
{
    LONG lrc;

    // open the line device
    lrc = lineOpen(mytapi->hTAPI, mytapi->dwLine, &mytapi->hLine,
                   mytapi->dwVersionToUse, 0, (DWORD)mytapi, 
                   LINECALLPRIVILEGE_OWNER, 
                   LINEMEDIAMODE_AUTOMATEDVOICE,
                   NULL);
    if (lrc)
        goto error;

    // bool indicates lineOpen called successfully
    mytapi->bLineopen = TRUE;

    // get the telephony icon and make it ours
    myDrawTAPIIcon(hWnd, mytapi);

    // receive all possible status messages for the 
    // line device and address
    lineSetStatusMessages(mytapi->hLine,
                          mytapi->pLinedevcaps->dwLineStates,
                          0);

    // set ring count for the no-message waiting situation
    lineSetNumRings (mytapi->hLine, 0, RINGCNT);
    lineGetNumRings(mytapi->hLine, 0, &mytapi->nRingCnt);

    // success
    return 0;

error:
    // error!  clean up and return error code

    telephonyShutdown(mytapi);

    return lrc;

} // end procedure (telephony initialize)
·
·
·
/////////////////////////////////////////////////////////////////////
//    mylineGetWaveID - get wave handle
////////////////////////////////////////////////////////////////////
LONG mylineGetWaveID (DWORD dwSelect, LPSTR waveDev, PMYTAPI mytapi)
{
DWORD dwWaveDev;
VARSTRING  *vs;
LONG lrc;
DWORD dwSize;

        // allocate memory for structure
        vs = (VARSTRING *) calloc (1, sizeof(VARSTRING));
        // set structure size
        vs->dwTotalSize = sizeof(VARSTRING);
        do {
                // get information into structure
                if (dwSelect == LINECALLSELECT_LINE)
                    lrc = lineGetID(mytapi->hLine, 0L, NULL, dwSelect, vs,
                                    waveDev);
                if (dwSelect == LINECALLSELECT_CALL)
                    lrc = lineGetID(mytapi->hLine, 0L, mytapi->hCall, dwSelect,
                                    vs, waveDev);
                // bomb out if error
                if (lrc)  {
                    free (vs);
                    return -1;
                }
                // reallocate and try again
                if (vs->dwTotalSize < vs->dwNeededSize) {
                        dwSize = vs->dwNeededSize;
                        free (vs);
                        vs = (VARSTRING *) calloc(1, dwSize);
                        vs->dwTotalSize = dwSize;
                        continue;
                } /* end if (need more space) */
                break; /* success  */
        } while (TRUE);

        // copy wave id
        dwWaveDev = (DWORD) *((DWORD *)((LPSTR)vs + vs->dwStringOffset));
        free (vs);

        return dwWaveDev;

} /* end function (mylineGetWaveID) */
/////////////////////////////////////////////////////////////////////
//    mylineGetDevCaps - get LINEDEVCAPS structure
////////////////////////////////////////////////////////////////////
LONG mylineGetDevCaps( PMYTAPI mytapi)
{
    LONG lrc;    
    DWORD dwsize;

    // if space already allocated for structure, free it up
    if (mytapi->bLinedevcapsalloced) {
        free (mytapi->pLinedevcaps);
        mytapi->bLinedevcapsalloced = FALSE;
    }

    // allocate memory for structure
    mytapi->pLinedevcaps = (LINEDEVCAPS *) calloc(1, sizeof(LINEDEVCAPS));
    if (!mytapi->pLinedevcaps)
        return LINEERR_NOMEM;
    mytapi->bLinedevcapsalloced = TRUE;
    // set structure size
    mytapi->pLinedevcaps->dwTotalSize = sizeof(LINEDEVCAPS);
    do {
        // get information into structure
        lrc = lineGetDevCaps(mytapi->hTAPI, mytapi->dwLine, 
                             mytapi->dwVersionToUse,
                             0, mytapi->pLinedevcaps);
        // bomb out if error
        if (lrc) {
            free (mytapi->pLinedevcaps);
            mytapi->bLinedevcapsalloced = FALSE;
            return lrc;
        }
        dwsize = mytapi->pLinedevcaps->dwNeededSize;
        // reallocate and try again
        if (mytapi->pLinedevcaps->dwTotalSize < dwsize) {
            free (mytapi->pLinedevcaps);
            mytapi->bLinedevcapsalloced = FALSE;
            mytapi->pLinedevcaps = (LINEDEVCAPS *) calloc(1, dwsize);
            if (!mytapi->pLinedevcaps)
                return LINEERR_NOMEM;
            mytapi->bLinedevcapsalloced = TRUE;
            mytapi->pLinedevcaps->dwTotalSize = dwsize;
            continue;
        }
        break;
    } while (TRUE);

    return lrc;
}
/////////////////////////////////////////////////////////////////////
//    mylineGetCallStatus - get LINECALLSTATUS structure
////////////////////////////////////////////////////////////////////
LONG mylineGetCallStatus( PMYTAPI mytapi)
{
    LONG lrc;
    DWORD dwsize;

    // if space already allocated for structure, free it up
    if (mytapi->bLinecallstatusalloced) {
        free (mytapi->pLinecallstatus);
        mytapi->bLinecallstatusalloced = FALSE;
    }

    // allocate memory for structure
    mytapi->pLinecallstatus = (LINECALLSTATUS *) calloc(1,
                                                        sizeof(LINECALLSTATUS));
    if (!mytapi->pLinecallstatus)
        return LINEERR_NOMEM;
    mytapi->bLinecallstatusalloced = TRUE;
    // set structure size
    mytapi->pLinecallstatus->dwTotalSize = sizeof(LINECALLSTATUS);

    do {
        // get information into structure
        lrc = lineGetCallStatus(mytapi->hCall, mytapi->pLinecallstatus);
        // bomb out if error
        if (lrc) {
            free (mytapi->pLinecallstatus);
            mytapi->bLinecallstatusalloced = FALSE;
            return lrc;
        }
// reallocate and try again
        dwsize = mytapi->pLinecallstatus->dwNeededSize;
        if (mytapi->pLinecallstatus->dwTotalSize < dwsize) {
            free (mytapi->pLinecallstatus);
            mytapi->bLinecallstatusalloced = FALSE;
            mytapi->pLinecallstatus = (LINECALLSTATUS *) calloc(1, dwsize);
            if (!mytapi->pLinecallstatus)
                return LINEERR_NOMEM;
            mytapi->bLinecallstatusalloced = TRUE;
            mytapi->pLinecallstatus->dwTotalSize = dwsize;
            continue;
        }
        break;
    } while (TRUE);

    return lrc;
}
/////////////////////////////////////////////////////////////////////
//    telephonyShutdown - mega functions to close line, shut down 
//        telephony, close modem handle, restore serial device 
//        configuration, and free up various allocated structures.
////////////////////////////////////////////////////////////////////
void telephonyShutdown( PMYTAPI mytapi)
{
// close line if open
    if (mytapi->bLineopen)
        lineClose(mytapi->hLine);
    // shutdown tapi if initialized
    if (mytapi->bInitialized)
        lineShutdown(mytapi->hTAPI);

    // free up various structures if allocated
    if (mytapi->bLinedevcapsalloced)
        free (mytapi->pLinedevcaps);
    if (mytapi->bLinedevstatusalloced)
        free (mytapi->pLinedevstatus);
    if (mytapi->bLinecallinfoalloced)
        free(mytapi->pLinecallinfo);
    if (mytapi->bLinecallstatusalloced)
        free(mytapi->pLinecallstatus);

    // set flags to indicate that the structures are no longer
    // allocated
    mytapi->bLinedevcapsalloced = FALSE;
    mytapi->bLinedevstatusalloced = FALSE;
    mytapi->bLineopen = FALSE;
    mytapi->bInitialized = FALSE;
    mytapi->bLinecallinfoalloced = FALSE;
    mytapi->bLinecallstatusalloced = FALSE;
    mytapi->bWaitForCall = FALSE;

} // end function (telephonyShutdown)
/////////////////////////////////////////////////////////////////////
//    LineCallBackProc - message function for TAPI events
////////////////////////////////////////////////////////////////////
/* callback function */
void FAR PASCAL LineCallBackProc(DWORD dwDevice,DWORD dwMessage,
                                 DWORD dwInstance,DWORD dwParam1,
                                 DWORD dwParam2,DWORD dwParam3)
{
    LONG lrc;
    PMYTAPI mytapi = (PMYTAPI)dwInstance;

    switch (dwMessage) {
       case LINE_CALLSTATE:
           processCallState (mytapi, dwDevice, dwParam1, dwParam3);
           break;
        case LINE_CLOSE:
            break;
        case LINE_LINEDEVSTATE:
            
    switch (dwParam1) {
       case LINEDEVSTATE_RINGING:
           mytapi->nRings = dwParam3;
              if (mytapi->bWaitForCall && mytapi->nRings == mytapi->nRingCnt) {
                        // answer incoming calls
                        lrc =  lineAnswer(mytapi->hCall,NULL,0);
                        if (!(lrc >0 )) {
                            ProcessTAPIError(lrc);
                            myMessageBox("Error answering call");
                        }
                        mytapi->nRings = 0;
                    }
                                
                    break;
            }
            break;

        case LINE_MONITORDIGITS:

            switch (dwParam2) {
                case LINEDIGITMODE_DTMF:
                {
                char name[30];

                    if (mytapi->iPlayState == PLAYSTATE_IDLE) {
                        if (LOBYTE(dwParam1) == '1') {
                              if (mytapi->h_waveout =playSound 
                                   (mytapi->dwWaveOutID,"pw.wav", hTTYWnd)) {
                              mytapi->iPlayState = PLAYSTATE_PASSWORD;
                              }
                        } else if (LOBYTE(dwParam1) == '2') {
                              if (mytapi->h_waveout =playSound (1,"msg-1.wav",
                                  hTTYWnd)) {
                               mytapi->iPlayState = PLAYSTATE_RECORD;
                               recordMessage (mytapi->dwWaveInID);
                            }
                        }
                    } else if (mytapi->iPlayState == PLAYSTATE_PASSWORD) {

                        if (LOBYTE(dwParam1) == 
                            mytapi->szPassword[mytapi->inx])
                            mytapi->inx++;
                        else
                            mytapi->inx = 0;
                        if (!mytapi->szPassword[mytapi->inx]) {
                            /* successful password */
                            // begin playing messages
                            mytapi->inx = 0;
                            if (mytapi->nMsgCnt > 0) {
                                mytapi->nPlayCnt = 0;
                                wsprintf(name, "msg-%d.wav", 
                                         mytapi->nPlayCnt);
                               if (mytapi->h_waveout =playSound 
                                      (mytapi->dwWaveOutID,name, hTTYWnd))
                                       mytapi->iPlayState =PLAYSTATE_PLAYBACK;
                            } else {
                               mytapi->h_waveout =playSound 
                                                    (mytapi->dwWaveOutID,
                                                     "nomsg.wav", hTTYWnd);
                            }
                        }
                    }
                    break;
                }
                case LINEDIGITMODE_DTMFEND:

                    break;
                default:
                    break;
            } //end switch
            break;
        case LINE_MONITORTONE:

            break;
        case LINE_REPLY:
            if (dwParam2 < 0)
                ProcessTAPIError (dwParam2);

        default:
            break;
    } //end switch

    return;

} /* LineCallBackProc */

·
·
·

/////////////////////////////////////////////////////////////////////
//    myMessageBox - easy message box function
////////////////////////////////////////////////////////////////////
void myMessageBox (LPSTR s)
{
    MessageBox (NULL, "Error", s, MB_OK);
}
/////////////////////////////////////////////////////////////////////
// processCallState 
////////////////////////////////////////////////////////////////////
void processCallState (PMYTAPI mytapi, DWORD dwDevice, DWORD dwState, 
                       DWORD dwPrivilege)
{
LONG lrc;
HMENU hMenu;

    switch (dwPrivilege) {
        case LINECALLPRIVILEGE_MONITOR:
            break;
        case LINECALLPRIVILEGE_OWNER:

            // update local call information
            mylineGetCallStatus(mytapi);

            // update menus
            hMenu = GetMenu(hTTYWnd);
            // answer call
            if (mytapi->pLinecallstatus->dwCallFeatures &
                                         LINECALLFEATURE_ANSWER)
               EnableMenuItem( hMenu, IDM_ANSWER, MF_ENABLED | MF_BYCOMMAND );
            else
               EnableMenuItem( hMenu, IDM_ANSWER, MF_GRAYED | MF_DISABLED |
                               MF_BYCOMMAND ) ;

            // save call handle and get device ids
            if (mytapi->hCall != (HCALL)dwDevice) {
                mytapi->hCall = (HCALL)dwDevice;

                mytapi->dwWaveInID = mylineGetWaveID(LINECALLSELECT_CALL,
                                                     "wave/in", mytapi);
                mytapi->dwWaveOutID = mylineGetWaveID(LINECALLSELECT_CALL,
                                                      "wave/out", mytapi);
            }

            
            break;
        default:
            break;
    } //end switch
    
    switch (dwState) {
        case LINECALLSTATE_IDLE:

            // deallocate call resources
            lineDeallocateCall (mytapi->hCall);
            mytapi->hCall = NULL;
            break;
·
·
·
        case LINECALLSTATE_CONNECTED:

           mytapi->h_waveout =playSound (mytapi->dwWaveOutID,"greeting.wav",
                                         hTTYWnd);
            mytapi->iPlayState = PLAYSTATE_IDLE;
            mytapi->inx = 0;

           lrc = lineMonitorDigits(mytapi->hCall, LINEDIGITMODE_DTMF);
            break;
        default:
            break;
    } //end switch

     return;
}

Figure 8   Handling MM_WOM_DONE

 case MM_WOM_DONE:
            /* Unprepare the header */
            waveOutUnprepareHeader((HWAVEOUT)wParam,(LPWAVEHDR)lParam,
                                   sizeof(WAVEHDR));
            waveOutClose((HWAVEOUT)wParam); /* close wave device */
            free (((LPWAVEHDR)lParam)->lpData); /* free the wave data */
            free ((LPWAVEHDR)lParam); /* free the header */
            if (mytapi.iPlayState == PLAYSTATE_PLAYBACK) {
                if (mytapi.nPlayCnt < mytapi.nMsgCnt) {
                    mytapi.nPlayCnt++;
                    wsprintf (name, "msg-%d.wav", mytapi.nPlayCnt);
                    mytapi.h_waveout=playSound (mytapi.dwWaveOutID, name, 
                                                hTTYWnd);
                } else {
                    mytapi.iPlayState = PLAYSTATE_IDLE;
                    mytapi.inx = 0;
                    mytapi.nPlayCnt = 0;
                    }

            } 
            break;

Figure 9   Handling LINE_CALLSTATE

 case LINE_CALLSTATE:
      // (all cases of dwParam1)
      switch (dwParam3) {
            case LINECALLPRIVILEGE_MONITOR:
            break;  // I don't have privilege to answer
            case LINECALLPRIVILEGE_OWNER:
                  // update local call information, menus
.
.
.
                  // save call handle and get device ids
                  if (mytapi.hCall != (HCALL)dwDevice) {
                      mytapi.hCall = (HCALL)dwDevice;
                      mytapi.dwWaveInID =
                         mylineGetWaveID(LINECALLSELECT_CALL, "wave/in");
                      mytapi.dwWaveOutID =
                         mylineGetWaveID(LINECALLSELECT_CALL, "wave/out");
                  }
                  break;
            default:
            break;
      } //end switch

Figure 10   Cleaning Up After Recording

 case MM_WIM_DATA:
      waveInUnprepareHeader (mytapi.h_wavein, (LPWAVEHDR)lParam,
                             sizeof(WAVEHDR));
      waveInClose (mytapi.h_wavein); /* close wave device */
      /* drop the call */
      if (mytapi.hCall) {
          if ((lrc = lineDrop (mytapi.hCall, NULL, 0)) < 0) {
              ProcessTAPIError (lrc);
              MessageBox (hTTYWnd, "Error dropping call", "", MB_OK);
          }
      }
      mytapi.nMsgCnt++;
      wsprintf (name, "msg-%d.wav", mytapi.nMsgCnt);
      saveMessage (name, (LPWAVEHDR)lParam); /* save the message */
      /* free 60s message buffer */
      GlobalFree ((HANDLE)((LPWAVEHDR)lParam)->dwUser);
      // set ring count for the message-waiting situation to implement
      // toll saver feature
      lineSetNumRings (mytapi.hLine, 0, max(0, RINGCNT-2));
      lineGetNumRings (mytapi.hLine, 0, &mytapi.nRingCnt);
      mytapi.iPlayState = PLAYSTATE_IDLE;
      mytapi.iPlaySubState = PLAYSUBSTATE_PASSWORD0;
      break;